s3:docs: Fix typo in man mount.cifs.
[Samba/gebeck_regimport.git] / libcli / cldap / cldap.c
blob191d0eeee49c1d6e4873dcb1ca20cbcecc3d1228
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 void 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;
180 c->recv_subreq = NULL;
182 in = talloc_zero(c, struct cldap_incoming);
183 if (!in) {
184 goto nomem;
187 ret = tdgram_recvfrom_recv(subreq,
188 &in->recv_errno,
190 &in->buf,
191 &in->src);
192 talloc_free(subreq);
193 subreq = NULL;
194 if (ret >= 0) {
195 in->len = ret;
197 if (ret == -1 && in->recv_errno == 0) {
198 in->recv_errno = EIO;
201 /* this function should free or steal 'in' */
202 cldap_socket_recv_dgram(c, in);
203 in = NULL;
205 if (!cldap_recvfrom_setup(c)) {
206 goto nomem;
209 return;
211 nomem:
212 talloc_free(subreq);
213 talloc_free(in);
214 /*TODO: call a dead socket handler */
215 return;
219 handle recv events on a cldap socket
221 static void cldap_socket_recv_dgram(struct cldap_socket *c,
222 struct cldap_incoming *in)
224 DATA_BLOB blob;
225 struct asn1_data *asn1;
226 void *p;
227 struct cldap_search_state *search;
228 NTSTATUS status;
230 if (in->recv_errno != 0) {
231 goto error;
234 blob = data_blob_const(in->buf, in->len);
236 asn1 = asn1_init(in);
237 if (!asn1) {
238 goto nomem;
241 if (!asn1_load(asn1, blob)) {
242 goto nomem;
245 in->ldap_msg = talloc(in, struct ldap_message);
246 if (in->ldap_msg == NULL) {
247 goto nomem;
250 /* this initial decode is used to find the message id */
251 status = ldap_decode(asn1, NULL, in->ldap_msg);
252 if (!NT_STATUS_IS_OK(status)) {
253 goto nterror;
256 /* find the pending request */
257 p = idr_find(c->searches.idr, in->ldap_msg->messageid);
258 if (p == NULL) {
259 if (!c->incoming.handler) {
260 goto done;
263 /* this function should free or steal 'in' */
264 c->incoming.handler(c, c->incoming.private_data, in);
265 return;
268 search = talloc_get_type(p, struct cldap_search_state);
269 search->response.in = talloc_move(search, &in);
270 search->response.asn1 = asn1;
271 search->response.asn1->ofs = 0;
273 tevent_req_done(search->req);
274 goto done;
276 nomem:
277 in->recv_errno = ENOMEM;
278 error:
279 status = map_nt_error_from_unix(in->recv_errno);
280 nterror:
281 /* in connected mode the first pending search gets the error */
282 if (!c->connected) {
283 /* otherwise we just ignore the error */
284 goto done;
286 if (!c->searches.list) {
287 goto done;
289 tevent_req_nterror(c->searches.list->req, status);
290 done:
291 talloc_free(in);
295 initialise a cldap_sock
297 NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx,
298 struct tevent_context *ev,
299 const struct tsocket_address *local_addr,
300 const struct tsocket_address *remote_addr,
301 struct cldap_socket **_cldap)
303 struct cldap_socket *c = NULL;
304 struct tsocket_address *any = NULL;
305 NTSTATUS status;
306 int ret;
308 c = talloc_zero(mem_ctx, struct cldap_socket);
309 if (!c) {
310 goto nomem;
313 if (!ev) {
314 ev = tevent_context_init(c);
315 if (!ev) {
316 goto nomem;
318 c->event.allow_poll = true;
320 c->event.ctx = ev;
322 if (!local_addr) {
323 ret = tsocket_address_inet_from_strings(c, "ip",
324 NULL, 0,
325 &any);
326 if (ret != 0) {
327 status = map_nt_error_from_unix(errno);
328 goto nterror;
330 local_addr = any;
333 c->searches.idr = idr_init(c);
334 if (!c->searches.idr) {
335 goto nomem;
338 ret = tdgram_inet_udp_socket(local_addr, remote_addr,
339 c, &c->sock);
340 if (ret != 0) {
341 status = map_nt_error_from_unix(errno);
342 goto nterror;
344 talloc_free(any);
346 if (remote_addr) {
347 c->connected = true;
350 c->send_queue = tevent_queue_create(c, "cldap_send_queue");
351 if (!c->send_queue) {
352 goto nomem;
355 talloc_set_destructor(c, cldap_socket_destructor);
357 *_cldap = c;
358 return NT_STATUS_OK;
360 nomem:
361 status = NT_STATUS_NO_MEMORY;
362 nterror:
363 talloc_free(c);
364 return status;
368 setup a handler for incoming requests
370 NTSTATUS cldap_set_incoming_handler(struct cldap_socket *c,
371 void (*handler)(struct cldap_socket *,
372 void *private_data,
373 struct cldap_incoming *),
374 void *private_data)
376 if (c->connected) {
377 return NT_STATUS_PIPE_CONNECTED;
380 /* if sync requests are allowed, we don't allow an incoming handler */
381 if (c->event.allow_poll) {
382 return NT_STATUS_INVALID_PIPE_STATE;
385 c->incoming.handler = handler;
386 c->incoming.private_data = private_data;
388 if (!cldap_recvfrom_setup(c)) {
389 ZERO_STRUCT(c->incoming);
390 return NT_STATUS_NO_MEMORY;
393 return NT_STATUS_OK;
396 struct cldap_reply_state {
397 struct tsocket_address *dest;
398 DATA_BLOB blob;
401 static void cldap_reply_state_destroy(struct tevent_req *subreq);
404 queue a cldap reply for send
406 NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
408 struct cldap_reply_state *state = NULL;
409 struct ldap_message *msg;
410 DATA_BLOB blob1, blob2;
411 NTSTATUS status;
412 struct tevent_req *subreq;
414 if (cldap->connected) {
415 return NT_STATUS_PIPE_CONNECTED;
418 if (!io->dest) {
419 return NT_STATUS_INVALID_ADDRESS;
422 state = talloc(cldap, struct cldap_reply_state);
423 NT_STATUS_HAVE_NO_MEMORY(state);
425 state->dest = tsocket_address_copy(io->dest, state);
426 if (!state->dest) {
427 goto nomem;
430 msg = talloc(state, struct ldap_message);
431 if (!msg) {
432 goto nomem;
435 msg->messageid = io->messageid;
436 msg->controls = NULL;
438 if (io->response) {
439 msg->type = LDAP_TAG_SearchResultEntry;
440 msg->r.SearchResultEntry = *io->response;
442 if (!ldap_encode(msg, NULL, &blob1, state)) {
443 status = NT_STATUS_INVALID_PARAMETER;
444 goto failed;
446 } else {
447 blob1 = data_blob(NULL, 0);
450 msg->type = LDAP_TAG_SearchResultDone;
451 msg->r.SearchResultDone = *io->result;
453 if (!ldap_encode(msg, NULL, &blob2, state)) {
454 status = NT_STATUS_INVALID_PARAMETER;
455 goto failed;
457 talloc_free(msg);
459 state->blob = data_blob_talloc(state, NULL, blob1.length + blob2.length);
460 if (!state->blob.data) {
461 goto nomem;
464 memcpy(state->blob.data, blob1.data, blob1.length);
465 memcpy(state->blob.data+blob1.length, blob2.data, blob2.length);
466 data_blob_free(&blob1);
467 data_blob_free(&blob2);
469 subreq = tdgram_sendto_queue_send(state,
470 cldap->event.ctx,
471 cldap->sock,
472 cldap->send_queue,
473 state->blob.data,
474 state->blob.length,
475 state->dest);
476 if (!subreq) {
477 goto nomem;
479 /* the callback will just free the state, as we don't need a result */
480 tevent_req_set_callback(subreq, cldap_reply_state_destroy, state);
482 return NT_STATUS_OK;
484 nomem:
485 status = NT_STATUS_NO_MEMORY;
486 failed:
487 talloc_free(state);
488 return status;
491 static void cldap_reply_state_destroy(struct tevent_req *subreq)
493 struct cldap_reply_state *state = tevent_req_callback_data(subreq,
494 struct cldap_reply_state);
496 /* we don't want to know the result here, we just free the state */
497 talloc_free(subreq);
498 talloc_free(state);
501 static int cldap_search_state_destructor(struct cldap_search_state *s)
503 if (s->caller.cldap) {
504 if (s->message_id != -1) {
505 idr_remove(s->caller.cldap->searches.idr, s->message_id);
506 s->message_id = -1;
508 DLIST_REMOVE(s->caller.cldap->searches.list, s);
509 cldap_recvfrom_stop(s->caller.cldap);
510 ZERO_STRUCT(s->caller);
513 return 0;
516 static void cldap_search_state_queue_done(struct tevent_req *subreq);
517 static void cldap_search_state_wakeup_done(struct tevent_req *subreq);
520 queue a cldap reply for send
522 struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
523 struct cldap_socket *cldap,
524 const struct cldap_search *io)
526 struct tevent_req *req, *subreq;
527 struct cldap_search_state *state = NULL;
528 struct ldap_message *msg;
529 struct ldap_SearchRequest *search;
530 struct timeval now;
531 struct timeval end;
532 uint32_t i;
533 int ret;
535 req = tevent_req_create(mem_ctx, &state,
536 struct cldap_search_state);
537 if (!req) {
538 return NULL;
540 ZERO_STRUCTP(state);
541 state->req = req;
542 state->caller.cldap = cldap;
543 state->message_id = -1;
545 talloc_set_destructor(state, cldap_search_state_destructor);
547 if (io->in.dest_address) {
548 if (cldap->connected) {
549 tevent_req_nterror(req, NT_STATUS_PIPE_CONNECTED);
550 goto post;
552 ret = tsocket_address_inet_from_strings(state,
553 "ip",
554 io->in.dest_address,
555 io->in.dest_port,
556 &state->request.dest);
557 if (ret != 0) {
558 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
559 goto post;
561 } else {
562 if (!cldap->connected) {
563 tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
564 goto post;
566 state->request.dest = NULL;
569 state->message_id = idr_get_new_random(cldap->searches.idr,
570 state, UINT16_MAX);
571 if (state->message_id == -1) {
572 tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
573 goto post;
576 msg = talloc(state, struct ldap_message);
577 if (tevent_req_nomem(msg, req)) {
578 goto post;
581 msg->messageid = state->message_id;
582 msg->type = LDAP_TAG_SearchRequest;
583 msg->controls = NULL;
584 search = &msg->r.SearchRequest;
586 search->basedn = "";
587 search->scope = LDAP_SEARCH_SCOPE_BASE;
588 search->deref = LDAP_DEREFERENCE_NEVER;
589 search->timelimit = 0;
590 search->sizelimit = 0;
591 search->attributesonly = false;
592 search->num_attributes = str_list_length(io->in.attributes);
593 search->attributes = io->in.attributes;
594 search->tree = ldb_parse_tree(msg, io->in.filter);
595 if (tevent_req_nomem(search->tree, req)) {
596 goto post;
599 if (!ldap_encode(msg, NULL, &state->request.blob, state)) {
600 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
601 goto post;
603 talloc_free(msg);
605 state->request.idx = 0;
606 state->request.delay = 10*1000*1000;
607 state->request.count = 3;
608 if (io->in.timeout > 0) {
609 state->request.delay = io->in.timeout * 1000 * 1000;
610 state->request.count = io->in.retries + 1;
613 now = tevent_timeval_current();
614 end = now;
615 for (i = 0; i < state->request.count; i++) {
616 end = tevent_timeval_add(&end, 0, state->request.delay);
619 if (!tevent_req_set_endtime(req, state->caller.cldap->event.ctx, end)) {
620 tevent_req_nomem(NULL, req);
621 goto post;
624 subreq = tdgram_sendto_queue_send(state,
625 state->caller.cldap->event.ctx,
626 state->caller.cldap->sock,
627 state->caller.cldap->send_queue,
628 state->request.blob.data,
629 state->request.blob.length,
630 state->request.dest);
631 if (tevent_req_nomem(subreq, req)) {
632 goto post;
634 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
636 DLIST_ADD_END(cldap->searches.list, state, struct cldap_search_state *);
638 return req;
640 post:
641 return tevent_req_post(req, cldap->event.ctx);
644 static void cldap_search_state_queue_done(struct tevent_req *subreq)
646 struct tevent_req *req = tevent_req_callback_data(subreq,
647 struct tevent_req);
648 struct cldap_search_state *state = tevent_req_data(req,
649 struct cldap_search_state);
650 ssize_t ret;
651 int sys_errno = 0;
652 struct timeval next;
654 ret = tdgram_sendto_queue_recv(subreq, &sys_errno);
655 talloc_free(subreq);
656 if (ret == -1) {
657 NTSTATUS status;
658 status = map_nt_error_from_unix(sys_errno);
659 DLIST_REMOVE(state->caller.cldap->searches.list, state);
660 ZERO_STRUCT(state->caller.cldap);
661 tevent_req_nterror(req, status);
662 return;
665 state->request.idx++;
667 /* wait for incoming traffic */
668 if (!cldap_recvfrom_setup(state->caller.cldap)) {
669 tevent_req_nomem(NULL, req);
670 return;
673 if (state->request.idx > state->request.count) {
674 /* we just wait for the response or a timeout */
675 return;
678 next = tevent_timeval_current_ofs(0, state->request.delay);
679 subreq = tevent_wakeup_send(state,
680 state->caller.cldap->event.ctx,
681 next);
682 if (tevent_req_nomem(subreq, req)) {
683 return;
685 tevent_req_set_callback(subreq, cldap_search_state_wakeup_done, req);
688 static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
690 struct tevent_req *req = tevent_req_callback_data(subreq,
691 struct tevent_req);
692 struct cldap_search_state *state = tevent_req_data(req,
693 struct cldap_search_state);
694 bool ok;
696 ok = tevent_wakeup_recv(subreq);
697 talloc_free(subreq);
698 if (!ok) {
699 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
700 return;
703 subreq = tdgram_sendto_queue_send(state,
704 state->caller.cldap->event.ctx,
705 state->caller.cldap->sock,
706 state->caller.cldap->send_queue,
707 state->request.blob.data,
708 state->request.blob.length,
709 state->request.dest);
710 if (tevent_req_nomem(subreq, req)) {
711 return;
713 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
717 receive a cldap reply
719 NTSTATUS cldap_search_recv(struct tevent_req *req,
720 TALLOC_CTX *mem_ctx,
721 struct cldap_search *io)
723 struct cldap_search_state *state = tevent_req_data(req,
724 struct cldap_search_state);
725 struct ldap_message *ldap_msg;
726 NTSTATUS status;
728 if (tevent_req_is_nterror(req, &status)) {
729 goto failed;
732 ldap_msg = talloc(mem_ctx, struct ldap_message);
733 if (!ldap_msg) {
734 goto nomem;
737 status = ldap_decode(state->response.asn1, NULL, ldap_msg);
738 if (!NT_STATUS_IS_OK(status)) {
739 goto failed;
742 ZERO_STRUCT(io->out);
744 /* the first possible form has a search result in first place */
745 if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
746 io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
747 if (!io->out.response) {
748 goto nomem;
750 *io->out.response = ldap_msg->r.SearchResultEntry;
752 /* decode the 2nd part */
753 status = ldap_decode(state->response.asn1, NULL, ldap_msg);
754 if (!NT_STATUS_IS_OK(status)) {
755 goto failed;
759 if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
760 status = NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
761 goto failed;
764 io->out.result = talloc(mem_ctx, struct ldap_Result);
765 if (!io->out.result) {
766 goto nomem;
768 *io->out.result = ldap_msg->r.SearchResultDone;
770 if (io->out.result->resultcode != LDAP_SUCCESS) {
771 status = NT_STATUS_LDAP(io->out.result->resultcode);
772 goto failed;
775 tevent_req_received(req);
776 return NT_STATUS_OK;
778 nomem:
779 status = NT_STATUS_NO_MEMORY;
780 failed:
781 tevent_req_received(req);
782 return status;
787 synchronous cldap search
789 NTSTATUS cldap_search(struct cldap_socket *cldap,
790 TALLOC_CTX *mem_ctx,
791 struct cldap_search *io)
793 struct tevent_req *req;
794 NTSTATUS status;
796 if (!cldap->event.allow_poll) {
797 return NT_STATUS_INVALID_PIPE_STATE;
800 if (cldap->searches.list) {
801 return NT_STATUS_PIPE_BUSY;
804 req = cldap_search_send(mem_ctx, cldap, io);
805 NT_STATUS_HAVE_NO_MEMORY(req);
807 if (!tevent_req_poll(req, cldap->event.ctx)) {
808 talloc_free(req);
809 return NT_STATUS_INTERNAL_ERROR;
812 status = cldap_search_recv(req, mem_ctx, io);
813 talloc_free(req);
815 return status;
818 struct cldap_netlogon_state {
819 struct cldap_search search;
822 static void cldap_netlogon_state_done(struct tevent_req *subreq);
824 queue a cldap netlogon for send
826 struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
827 struct cldap_socket *cldap,
828 const struct cldap_netlogon *io)
830 struct tevent_req *req, *subreq;
831 struct cldap_netlogon_state *state;
832 char *filter;
833 static const char * const attr[] = { "NetLogon", NULL };
835 req = tevent_req_create(mem_ctx, &state,
836 struct cldap_netlogon_state);
837 if (!req) {
838 return NULL;
841 filter = talloc_asprintf(state, "(&(NtVer=%s)",
842 ldap_encode_ndr_uint32(state, io->in.version));
843 if (tevent_req_nomem(filter, req)) {
844 goto post;
846 if (io->in.user) {
847 filter = talloc_asprintf_append_buffer(filter, "(User=%s)", io->in.user);
848 if (tevent_req_nomem(filter, req)) {
849 goto post;
852 if (io->in.host) {
853 filter = talloc_asprintf_append_buffer(filter, "(Host=%s)", io->in.host);
854 if (tevent_req_nomem(filter, req)) {
855 goto post;
858 if (io->in.realm) {
859 filter = talloc_asprintf_append_buffer(filter, "(DnsDomain=%s)", io->in.realm);
860 if (tevent_req_nomem(filter, req)) {
861 goto post;
864 if (io->in.acct_control != -1) {
865 filter = talloc_asprintf_append_buffer(filter, "(AAC=%s)",
866 ldap_encode_ndr_uint32(state, io->in.acct_control));
867 if (tevent_req_nomem(filter, req)) {
868 goto post;
871 if (io->in.domain_sid) {
872 struct dom_sid *sid = dom_sid_parse_talloc(state, io->in.domain_sid);
873 if (tevent_req_nomem(sid, req)) {
874 goto post;
876 filter = talloc_asprintf_append_buffer(filter, "(domainSid=%s)",
877 ldap_encode_ndr_dom_sid(state, sid));
878 if (tevent_req_nomem(filter, req)) {
879 goto post;
882 if (io->in.domain_guid) {
883 struct GUID guid;
884 NTSTATUS status;
885 status = GUID_from_string(io->in.domain_guid, &guid);
886 if (tevent_req_nterror(req, status)) {
887 goto post;
889 filter = talloc_asprintf_append_buffer(filter, "(DomainGuid=%s)",
890 ldap_encode_ndr_GUID(state, &guid));
891 if (tevent_req_nomem(filter, req)) {
892 goto post;
895 filter = talloc_asprintf_append_buffer(filter, ")");
896 if (tevent_req_nomem(filter, req)) {
897 goto post;
900 if (io->in.dest_address) {
901 state->search.in.dest_address = talloc_strdup(state,
902 io->in.dest_address);
903 if (tevent_req_nomem(state->search.in.dest_address, req)) {
904 goto post;
906 state->search.in.dest_port = io->in.dest_port;
907 } else {
908 state->search.in.dest_address = NULL;
909 state->search.in.dest_port = 0;
911 state->search.in.filter = filter;
912 state->search.in.attributes = attr;
913 state->search.in.timeout = 2;
914 state->search.in.retries = 2;
916 subreq = cldap_search_send(state, cldap, &state->search);
917 if (tevent_req_nomem(subreq, req)) {
918 goto post;
920 tevent_req_set_callback(subreq, cldap_netlogon_state_done, req);
922 return req;
923 post:
924 return tevent_req_post(req, cldap->event.ctx);
927 static void cldap_netlogon_state_done(struct tevent_req *subreq)
929 struct tevent_req *req = tevent_req_callback_data(subreq,
930 struct tevent_req);
931 struct cldap_netlogon_state *state = tevent_req_data(req,
932 struct cldap_netlogon_state);
933 NTSTATUS status;
935 status = cldap_search_recv(subreq, state, &state->search);
936 talloc_free(subreq);
938 if (tevent_req_nterror(req, status)) {
939 return;
942 tevent_req_done(req);
946 receive a cldap netlogon reply
948 NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
949 struct smb_iconv_convenience *iconv_convenience,
950 TALLOC_CTX *mem_ctx,
951 struct cldap_netlogon *io)
953 struct cldap_netlogon_state *state = tevent_req_data(req,
954 struct cldap_netlogon_state);
955 NTSTATUS status;
956 DATA_BLOB *data;
958 if (tevent_req_is_nterror(req, &status)) {
959 goto failed;
962 if (state->search.out.response == NULL) {
963 status = NT_STATUS_NOT_FOUND;
964 goto failed;
967 if (state->search.out.response->num_attributes != 1 ||
968 strcasecmp(state->search.out.response->attributes[0].name, "netlogon") != 0 ||
969 state->search.out.response->attributes[0].num_values != 1 ||
970 state->search.out.response->attributes[0].values->length < 2) {
971 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
972 goto failed;
974 data = state->search.out.response->attributes[0].values;
976 status = pull_netlogon_samlogon_response(data, mem_ctx,
977 iconv_convenience,
978 &io->out.netlogon);
979 if (!NT_STATUS_IS_OK(status)) {
980 goto failed;
983 if (io->in.map_response) {
984 map_netlogon_samlogon_response(&io->out.netlogon);
987 status = NT_STATUS_OK;
988 failed:
989 tevent_req_received(req);
990 return status;
994 sync cldap netlogon search
996 NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
997 struct smb_iconv_convenience *iconv_convenience,
998 TALLOC_CTX *mem_ctx,
999 struct cldap_netlogon *io)
1001 struct tevent_req *req;
1002 NTSTATUS status;
1004 if (!cldap->event.allow_poll) {
1005 return NT_STATUS_INVALID_PIPE_STATE;
1008 if (cldap->searches.list) {
1009 return NT_STATUS_PIPE_BUSY;
1012 req = cldap_netlogon_send(mem_ctx, cldap, io);
1013 NT_STATUS_HAVE_NO_MEMORY(req);
1015 if (!tevent_req_poll(req, cldap->event.ctx)) {
1016 talloc_free(req);
1017 return NT_STATUS_INTERNAL_ERROR;
1020 status = cldap_netlogon_recv(req, iconv_convenience, mem_ctx, io);
1021 talloc_free(req);
1023 return status;
1028 send an empty reply (used on any error, so the client doesn't keep waiting
1029 or send the bad request again)
1031 NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
1032 uint32_t message_id,
1033 struct tsocket_address *dest)
1035 NTSTATUS status;
1036 struct cldap_reply reply;
1037 struct ldap_Result result;
1039 reply.messageid = message_id;
1040 reply.dest = dest;
1041 reply.response = NULL;
1042 reply.result = &result;
1044 ZERO_STRUCT(result);
1046 status = cldap_reply_send(cldap, &reply);
1048 return status;
1052 send an error reply (used on any error, so the client doesn't keep waiting
1053 or send the bad request again)
1055 NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
1056 uint32_t message_id,
1057 struct tsocket_address *dest,
1058 int resultcode,
1059 const char *errormessage)
1061 NTSTATUS status;
1062 struct cldap_reply reply;
1063 struct ldap_Result result;
1065 reply.messageid = message_id;
1066 reply.dest = dest;
1067 reply.response = NULL;
1068 reply.result = &result;
1070 ZERO_STRUCT(result);
1071 result.resultcode = resultcode;
1072 result.errormessage = errormessage;
1074 status = cldap_reply_send(cldap, &reply);
1076 return status;
1081 send a netlogon reply
1083 NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
1084 struct smb_iconv_convenience *iconv_convenience,
1085 uint32_t message_id,
1086 struct tsocket_address *dest,
1087 uint32_t version,
1088 struct netlogon_samlogon_response *netlogon)
1090 NTSTATUS status;
1091 struct cldap_reply reply;
1092 struct ldap_SearchResEntry response;
1093 struct ldap_Result result;
1094 TALLOC_CTX *tmp_ctx = talloc_new(cldap);
1095 DATA_BLOB blob;
1097 status = push_netlogon_samlogon_response(&blob, tmp_ctx,
1098 iconv_convenience,
1099 netlogon);
1100 if (!NT_STATUS_IS_OK(status)) {
1101 talloc_free(tmp_ctx);
1102 return status;
1104 reply.messageid = message_id;
1105 reply.dest = dest;
1106 reply.response = &response;
1107 reply.result = &result;
1109 ZERO_STRUCT(result);
1111 response.dn = "";
1112 response.num_attributes = 1;
1113 response.attributes = talloc(tmp_ctx, struct ldb_message_element);
1114 NT_STATUS_HAVE_NO_MEMORY(response.attributes);
1115 response.attributes->name = "netlogon";
1116 response.attributes->num_values = 1;
1117 response.attributes->values = &blob;
1119 status = cldap_reply_send(cldap, &reply);
1121 talloc_free(tmp_ctx);
1123 return status;