lib/clap fix compiler warnings
[Samba.git] / libcli / cldap / cldap.c
blobeb4f102e6ab1d318c0b0b5ceaa5b440f8b4baf23
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;
64 /* the queue for outgoing dgrams */
65 struct tevent_queue *send_queue;
67 /* do we have an async tsocket_recvfrom request pending */
68 struct tevent_req *recv_subreq;
70 struct {
71 /* a queue of pending search requests */
72 struct cldap_search_state *list;
74 /* mapping from message_id to pending request */
75 struct idr_context *idr;
76 } searches;
78 /* what to do with incoming request packets */
79 struct {
80 struct tevent_context *ev;
81 void (*handler)(struct cldap_socket *,
82 void *private_data,
83 struct cldap_incoming *);
84 void *private_data;
85 } incoming;
88 struct cldap_search_state {
89 struct cldap_search_state *prev, *next;
91 struct {
92 struct tevent_context *ev;
93 struct cldap_socket *cldap;
94 } caller;
96 int message_id;
98 struct {
99 uint32_t idx;
100 uint32_t delay;
101 uint32_t count;
102 struct tsocket_address *dest;
103 DATA_BLOB blob;
104 } request;
106 struct {
107 struct cldap_incoming *in;
108 struct asn1_data *asn1;
109 } response;
111 struct tevent_req *req;
114 static int cldap_socket_destructor(struct cldap_socket *c)
116 while (c->searches.list) {
117 struct cldap_search_state *s = c->searches.list;
118 DLIST_REMOVE(c->searches.list, s);
119 ZERO_STRUCT(s->caller);
122 talloc_free(c->recv_subreq);
123 talloc_free(c->send_queue);
124 talloc_free(c->sock);
125 return 0;
128 static void cldap_recvfrom_done(struct tevent_req *subreq);
130 static bool cldap_recvfrom_setup(struct cldap_socket *c)
132 struct tevent_context *ev;
134 if (c->recv_subreq) {
135 return true;
138 if (!c->searches.list && !c->incoming.handler) {
139 return true;
142 ev = c->incoming.ev;
143 if (ev == NULL) {
144 ev = c->searches.list->caller.ev;
147 c->recv_subreq = tdgram_recvfrom_send(c, ev, 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);
218 handle recv events on a cldap socket
220 static bool cldap_socket_recv_dgram(struct cldap_socket *c,
221 struct cldap_incoming *in)
223 DATA_BLOB blob;
224 struct asn1_data *asn1;
225 void *p;
226 struct cldap_search_state *search;
227 NTSTATUS status;
229 if (in->recv_errno != 0) {
230 goto error;
233 blob = data_blob_const(in->buf, in->len);
235 asn1 = asn1_init(in);
236 if (!asn1) {
237 goto nomem;
240 if (!asn1_load(asn1, blob)) {
241 goto nomem;
244 in->ldap_msg = talloc(in, struct ldap_message);
245 if (in->ldap_msg == NULL) {
246 goto nomem;
249 /* this initial decode is used to find the message id */
250 status = ldap_decode(asn1, NULL, in->ldap_msg);
251 if (!NT_STATUS_IS_OK(status)) {
252 goto nterror;
255 /* find the pending request */
256 p = idr_find(c->searches.idr, in->ldap_msg->messageid);
257 if (p == NULL) {
258 if (!c->incoming.handler) {
259 TALLOC_FREE(in);
260 return true;
263 /* this function should free or steal 'in' */
264 c->incoming.handler(c, c->incoming.private_data, in);
265 return false;
268 search = talloc_get_type_abort(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 DLIST_REMOVE(c->searches.list, search);
275 if (cldap_recvfrom_setup(c)) {
276 tevent_req_done(search->req);
277 return true;
281 * This request was ok, just defer the notify of the caller
282 * and then just fail the next request if needed
284 tevent_req_defer_callback(search->req, search->caller.ev);
285 tevent_req_done(search->req);
287 status = NT_STATUS_NO_MEMORY;
288 /* in is NULL it this point */
289 goto nterror;
290 nomem:
291 in->recv_errno = ENOMEM;
292 error:
293 status = map_nt_error_from_unix_common(in->recv_errno);
294 nterror:
295 TALLOC_FREE(in);
296 /* in connected mode the first pending search gets the error */
297 if (!c->connected) {
298 /* otherwise we just ignore the error */
299 return false;
301 if (!c->searches.list) {
302 return false;
305 * We might called tevent_req_done() for a successful
306 * search before, so we better deliver the failure
307 * after the success, that is why we better also
308 * use tevent_req_defer_callback() here.
310 tevent_req_defer_callback(c->searches.list->req,
311 c->searches.list->caller.ev);
312 tevent_req_nterror(c->searches.list->req, status);
313 return false;
317 initialise a cldap_sock
319 NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx,
320 const struct tsocket_address *local_addr,
321 const struct tsocket_address *remote_addr,
322 struct cldap_socket **_cldap)
324 struct cldap_socket *c = NULL;
325 struct tsocket_address *any = NULL;
326 NTSTATUS status;
327 int ret;
328 const char *fam = NULL;
330 if (local_addr == NULL && remote_addr == NULL) {
331 return NT_STATUS_INVALID_PARAMETER_MIX;
334 if (remote_addr) {
335 bool is_ipv4;
336 bool is_ipv6;
338 is_ipv4 = tsocket_address_is_inet(remote_addr, "ipv4");
339 is_ipv6 = tsocket_address_is_inet(remote_addr, "ipv6");
341 if (is_ipv4) {
342 fam = "ipv4";
343 } else if (is_ipv6) {
344 fam = "ipv6";
345 } else {
346 return NT_STATUS_INVALID_ADDRESS;
350 c = talloc_zero(mem_ctx, struct cldap_socket);
351 if (!c) {
352 goto nomem;
355 if (!local_addr) {
357 * Here we know the address family of the remote address.
359 if (fam == NULL) {
360 return NT_STATUS_INVALID_PARAMETER_MIX;
363 ret = tsocket_address_inet_from_strings(c, fam,
364 NULL, 0,
365 &any);
366 if (ret != 0) {
367 status = map_nt_error_from_unix_common(errno);
368 goto nterror;
370 local_addr = any;
373 c->searches.idr = idr_init(c);
374 if (!c->searches.idr) {
375 goto nomem;
378 ret = tdgram_inet_udp_socket(local_addr, remote_addr,
379 c, &c->sock);
380 if (ret != 0) {
381 status = map_nt_error_from_unix_common(errno);
382 goto nterror;
384 talloc_free(any);
386 if (remote_addr) {
387 c->connected = true;
390 c->send_queue = tevent_queue_create(c, "cldap_send_queue");
391 if (!c->send_queue) {
392 goto nomem;
395 talloc_set_destructor(c, cldap_socket_destructor);
397 *_cldap = c;
398 return NT_STATUS_OK;
400 nomem:
401 status = NT_STATUS_NO_MEMORY;
402 nterror:
403 talloc_free(c);
404 return status;
408 setup a handler for incoming requests
410 NTSTATUS cldap_set_incoming_handler(struct cldap_socket *c,
411 struct tevent_context *ev,
412 void (*handler)(struct cldap_socket *,
413 void *private_data,
414 struct cldap_incoming *),
415 void *private_data)
417 if (c->connected) {
418 return NT_STATUS_PIPE_CONNECTED;
421 c->incoming.ev = ev;
422 c->incoming.handler = handler;
423 c->incoming.private_data = private_data;
425 if (!cldap_recvfrom_setup(c)) {
426 ZERO_STRUCT(c->incoming);
427 return NT_STATUS_NO_MEMORY;
430 return NT_STATUS_OK;
433 struct cldap_reply_state {
434 struct tsocket_address *dest;
435 DATA_BLOB blob;
438 static void cldap_reply_state_destroy(struct tevent_req *subreq);
441 queue a cldap reply for send
443 NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
445 struct cldap_reply_state *state = NULL;
446 struct ldap_message *msg;
447 DATA_BLOB blob1, blob2;
448 NTSTATUS status;
449 struct tevent_req *subreq;
451 if (cldap->connected) {
452 return NT_STATUS_PIPE_CONNECTED;
455 if (cldap->incoming.ev == NULL) {
456 return NT_STATUS_INVALID_PIPE_STATE;
459 if (!io->dest) {
460 return NT_STATUS_INVALID_ADDRESS;
463 state = talloc(cldap, struct cldap_reply_state);
464 NT_STATUS_HAVE_NO_MEMORY(state);
466 state->dest = tsocket_address_copy(io->dest, state);
467 if (!state->dest) {
468 goto nomem;
471 msg = talloc(state, struct ldap_message);
472 if (!msg) {
473 goto nomem;
476 msg->messageid = io->messageid;
477 msg->controls = NULL;
479 if (io->response) {
480 msg->type = LDAP_TAG_SearchResultEntry;
481 msg->r.SearchResultEntry = *io->response;
483 if (!ldap_encode(msg, NULL, &blob1, state)) {
484 status = NT_STATUS_INVALID_PARAMETER;
485 goto failed;
487 } else {
488 blob1 = data_blob(NULL, 0);
491 msg->type = LDAP_TAG_SearchResultDone;
492 msg->r.SearchResultDone = *io->result;
494 if (!ldap_encode(msg, NULL, &blob2, state)) {
495 status = NT_STATUS_INVALID_PARAMETER;
496 goto failed;
498 talloc_free(msg);
500 state->blob = data_blob_talloc(state, NULL, blob1.length + blob2.length);
501 if (!state->blob.data) {
502 goto nomem;
505 memcpy(state->blob.data, blob1.data, blob1.length);
506 memcpy(state->blob.data+blob1.length, blob2.data, blob2.length);
507 data_blob_free(&blob1);
508 data_blob_free(&blob2);
510 subreq = tdgram_sendto_queue_send(state,
511 cldap->incoming.ev,
512 cldap->sock,
513 cldap->send_queue,
514 state->blob.data,
515 state->blob.length,
516 state->dest);
517 if (!subreq) {
518 goto nomem;
520 /* the callback will just free the state, as we don't need a result */
521 tevent_req_set_callback(subreq, cldap_reply_state_destroy, state);
523 return NT_STATUS_OK;
525 nomem:
526 status = NT_STATUS_NO_MEMORY;
527 failed:
528 talloc_free(state);
529 return status;
532 static void cldap_reply_state_destroy(struct tevent_req *subreq)
534 struct cldap_reply_state *state = tevent_req_callback_data(subreq,
535 struct cldap_reply_state);
537 /* we don't want to know the result here, we just free the state */
538 talloc_free(subreq);
539 talloc_free(state);
542 static int cldap_search_state_destructor(struct cldap_search_state *s)
544 if (s->caller.cldap) {
545 if (s->message_id != -1) {
546 idr_remove(s->caller.cldap->searches.idr, s->message_id);
547 s->message_id = -1;
549 DLIST_REMOVE(s->caller.cldap->searches.list, s);
550 cldap_recvfrom_stop(s->caller.cldap);
551 ZERO_STRUCT(s->caller);
554 return 0;
557 static void cldap_search_state_queue_done(struct tevent_req *subreq);
558 static void cldap_search_state_wakeup_done(struct tevent_req *subreq);
561 queue a cldap reply for send
563 struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
564 struct tevent_context *ev,
565 struct cldap_socket *cldap,
566 const struct cldap_search *io)
568 struct tevent_req *req, *subreq;
569 struct cldap_search_state *state = NULL;
570 struct ldap_message *msg;
571 struct ldap_SearchRequest *search;
572 struct timeval now;
573 struct timeval end;
574 uint32_t i;
575 int ret;
577 req = tevent_req_create(mem_ctx, &state,
578 struct cldap_search_state);
579 if (!req) {
580 return NULL;
582 ZERO_STRUCTP(state);
583 state->caller.ev = ev;
584 state->req = req;
585 state->caller.cldap = cldap;
586 state->message_id = -1;
588 talloc_set_destructor(state, cldap_search_state_destructor);
590 if (io->in.dest_address) {
591 if (cldap->connected) {
592 tevent_req_nterror(req, NT_STATUS_PIPE_CONNECTED);
593 goto post;
595 ret = tsocket_address_inet_from_strings(state,
596 "ip",
597 io->in.dest_address,
598 io->in.dest_port,
599 &state->request.dest);
600 if (ret != 0) {
601 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
602 goto post;
604 } else {
605 if (!cldap->connected) {
606 tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
607 goto post;
609 state->request.dest = NULL;
612 state->message_id = idr_get_new_random(cldap->searches.idr,
613 state, UINT16_MAX);
614 if (state->message_id == -1) {
615 tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
616 goto post;
619 msg = talloc(state, struct ldap_message);
620 if (tevent_req_nomem(msg, req)) {
621 goto post;
624 msg->messageid = state->message_id;
625 msg->type = LDAP_TAG_SearchRequest;
626 msg->controls = NULL;
627 search = &msg->r.SearchRequest;
629 search->basedn = "";
630 search->scope = LDAP_SEARCH_SCOPE_BASE;
631 search->deref = LDAP_DEREFERENCE_NEVER;
632 search->timelimit = 0;
633 search->sizelimit = 0;
634 search->attributesonly = false;
635 search->num_attributes = str_list_length(io->in.attributes);
636 search->attributes = io->in.attributes;
637 search->tree = ldb_parse_tree(msg, io->in.filter);
638 if (tevent_req_nomem(search->tree, req)) {
639 goto post;
642 if (!ldap_encode(msg, NULL, &state->request.blob, state)) {
643 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
644 goto post;
646 talloc_free(msg);
648 state->request.idx = 0;
649 state->request.delay = 10*1000*1000;
650 state->request.count = 3;
651 if (io->in.timeout > 0) {
652 state->request.delay = io->in.timeout * 1000 * 1000;
653 state->request.count = io->in.retries + 1;
656 now = tevent_timeval_current();
657 end = now;
658 for (i = 0; i < state->request.count; i++) {
659 end = tevent_timeval_add(&end, state->request.delay / 1000000,
660 state->request.delay % 1000000);
663 if (!tevent_req_set_endtime(req, state->caller.ev, end)) {
664 tevent_req_oom(req);
665 goto post;
668 subreq = tdgram_sendto_queue_send(state,
669 state->caller.ev,
670 state->caller.cldap->sock,
671 state->caller.cldap->send_queue,
672 state->request.blob.data,
673 state->request.blob.length,
674 state->request.dest);
675 if (tevent_req_nomem(subreq, req)) {
676 goto post;
678 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
680 DLIST_ADD_END(cldap->searches.list, state, struct cldap_search_state *);
682 return req;
684 post:
685 return tevent_req_post(req, state->caller.ev);
688 static void cldap_search_state_queue_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 ssize_t ret;
695 int sys_errno = 0;
696 struct timeval next;
698 ret = tdgram_sendto_queue_recv(subreq, &sys_errno);
699 talloc_free(subreq);
700 if (ret == -1) {
701 NTSTATUS status;
702 status = map_nt_error_from_unix_common(sys_errno);
703 DLIST_REMOVE(state->caller.cldap->searches.list, state);
704 ZERO_STRUCT(state->caller.cldap);
705 tevent_req_nterror(req, status);
706 return;
709 state->request.idx++;
711 /* wait for incoming traffic */
712 if (!cldap_recvfrom_setup(state->caller.cldap)) {
713 tevent_req_oom(req);
714 return;
717 if (state->request.idx > state->request.count) {
718 /* we just wait for the response or a timeout */
719 return;
722 next = tevent_timeval_current_ofs(state->request.delay / 1000000,
723 state->request.delay % 1000000);
724 subreq = tevent_wakeup_send(state,
725 state->caller.ev,
726 next);
727 if (tevent_req_nomem(subreq, req)) {
728 return;
730 tevent_req_set_callback(subreq, cldap_search_state_wakeup_done, req);
733 static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
735 struct tevent_req *req = tevent_req_callback_data(subreq,
736 struct tevent_req);
737 struct cldap_search_state *state = tevent_req_data(req,
738 struct cldap_search_state);
739 bool ok;
741 ok = tevent_wakeup_recv(subreq);
742 talloc_free(subreq);
743 if (!ok) {
744 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
745 return;
748 subreq = tdgram_sendto_queue_send(state,
749 state->caller.ev,
750 state->caller.cldap->sock,
751 state->caller.cldap->send_queue,
752 state->request.blob.data,
753 state->request.blob.length,
754 state->request.dest);
755 if (tevent_req_nomem(subreq, req)) {
756 return;
758 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
762 receive a cldap reply
764 NTSTATUS cldap_search_recv(struct tevent_req *req,
765 TALLOC_CTX *mem_ctx,
766 struct cldap_search *io)
768 struct cldap_search_state *state = tevent_req_data(req,
769 struct cldap_search_state);
770 struct ldap_message *ldap_msg;
771 NTSTATUS status;
773 if (tevent_req_is_nterror(req, &status)) {
774 goto failed;
777 ldap_msg = talloc(mem_ctx, struct ldap_message);
778 if (!ldap_msg) {
779 goto nomem;
782 status = ldap_decode(state->response.asn1, NULL, ldap_msg);
783 if (!NT_STATUS_IS_OK(status)) {
784 goto failed;
787 ZERO_STRUCT(io->out);
789 /* the first possible form has a search result in first place */
790 if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
791 io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
792 if (!io->out.response) {
793 goto nomem;
795 *io->out.response = ldap_msg->r.SearchResultEntry;
797 /* decode the 2nd part */
798 status = ldap_decode(state->response.asn1, NULL, ldap_msg);
799 if (!NT_STATUS_IS_OK(status)) {
800 goto failed;
804 if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
805 status = NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
806 goto failed;
809 io->out.result = talloc(mem_ctx, struct ldap_Result);
810 if (!io->out.result) {
811 goto nomem;
813 *io->out.result = ldap_msg->r.SearchResultDone;
815 if (io->out.result->resultcode != LDAP_SUCCESS) {
816 status = NT_STATUS_LDAP(io->out.result->resultcode);
817 goto failed;
820 tevent_req_received(req);
821 return NT_STATUS_OK;
823 nomem:
824 status = NT_STATUS_NO_MEMORY;
825 failed:
826 tevent_req_received(req);
827 return status;
832 synchronous cldap search
834 NTSTATUS cldap_search(struct cldap_socket *cldap,
835 TALLOC_CTX *mem_ctx,
836 struct cldap_search *io)
838 TALLOC_CTX *frame;
839 struct tevent_req *req;
840 struct tevent_context *ev;
841 NTSTATUS status;
843 if (cldap->searches.list) {
844 return NT_STATUS_PIPE_BUSY;
847 if (cldap->incoming.handler) {
848 return NT_STATUS_INVALID_PIPE_STATE;
851 frame = talloc_stackframe();
853 ev = samba_tevent_context_init(frame);
854 if (ev == NULL) {
855 TALLOC_FREE(frame);
856 return NT_STATUS_NO_MEMORY;
859 req = cldap_search_send(mem_ctx, ev, cldap, io);
860 if (req == NULL) {
861 TALLOC_FREE(frame);
862 return NT_STATUS_NO_MEMORY;
865 if (!tevent_req_poll(req, ev)) {
866 status = map_nt_error_from_unix_common(errno);
867 TALLOC_FREE(frame);
868 return status;
871 status = cldap_search_recv(req, mem_ctx, io);
872 if (!NT_STATUS_IS_OK(status)) {
873 TALLOC_FREE(frame);
874 return status;
877 TALLOC_FREE(frame);
878 return NT_STATUS_OK;
881 struct cldap_netlogon_state {
882 struct cldap_search search;
885 char *cldap_netlogon_create_filter(TALLOC_CTX *mem_ctx,
886 const struct cldap_netlogon *io)
888 char *filter;
890 filter = talloc_asprintf(mem_ctx, "(&(NtVer=%s)",
891 ldap_encode_ndr_uint32(mem_ctx, io->in.version));
892 if (filter == NULL)
893 return NULL;
895 if (io->in.user) {
896 filter = talloc_asprintf_append_buffer(filter, "(User=%s)", io->in.user);
897 if (filter == NULL) {
898 return NULL;
901 if (io->in.host) {
902 filter = talloc_asprintf_append_buffer(filter, "(Host=%s)", io->in.host);
903 if (filter == NULL) {
904 return NULL;
907 if (io->in.realm) {
908 filter = talloc_asprintf_append_buffer(filter, "(DnsDomain=%s)", io->in.realm);
909 if (filter == NULL) {
910 return NULL;
913 if (io->in.acct_control != -1) {
914 filter = talloc_asprintf_append_buffer(filter, "(AAC=%s)",
915 ldap_encode_ndr_uint32(mem_ctx, io->in.acct_control));
916 if (filter == NULL) {
917 return NULL;
920 if (io->in.domain_sid) {
921 struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, io->in.domain_sid);
922 if (filter == NULL) {
923 return NULL;
925 filter = talloc_asprintf_append_buffer(filter, "(domainSid=%s)",
926 ldap_encode_ndr_dom_sid(mem_ctx, sid));
927 if (filter == NULL) {
928 return NULL;
931 if (io->in.domain_guid) {
932 struct GUID guid;
933 GUID_from_string(io->in.domain_guid, &guid);
934 if (filter == NULL) {
935 return NULL;
937 filter = talloc_asprintf_append_buffer(filter, "(DomainGuid=%s)",
938 ldap_encode_ndr_GUID(mem_ctx, &guid));
939 if (filter == NULL) {
940 return NULL;
943 filter = talloc_asprintf_append_buffer(filter, ")");
945 return filter;
948 static void cldap_netlogon_state_done(struct tevent_req *subreq);
950 queue a cldap netlogon for send
952 struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
953 struct tevent_context *ev,
954 struct cldap_socket *cldap,
955 const struct cldap_netlogon *io)
957 struct tevent_req *req, *subreq;
958 struct cldap_netlogon_state *state;
959 char *filter;
960 static const char * const attr[] = { "NetLogon", NULL };
962 req = tevent_req_create(mem_ctx, &state,
963 struct cldap_netlogon_state);
964 if (!req) {
965 return NULL;
968 filter = cldap_netlogon_create_filter(state, io);
969 if (tevent_req_nomem(filter, req)) {
970 goto post;
973 if (io->in.dest_address) {
974 state->search.in.dest_address = talloc_strdup(state,
975 io->in.dest_address);
976 if (tevent_req_nomem(state->search.in.dest_address, req)) {
977 goto post;
979 state->search.in.dest_port = io->in.dest_port;
980 } else {
981 state->search.in.dest_address = NULL;
982 state->search.in.dest_port = 0;
984 state->search.in.filter = filter;
985 state->search.in.attributes = attr;
986 state->search.in.timeout = 2;
987 state->search.in.retries = 2;
989 subreq = cldap_search_send(state, ev, cldap, &state->search);
990 if (tevent_req_nomem(subreq, req)) {
991 goto post;
993 tevent_req_set_callback(subreq, cldap_netlogon_state_done, req);
995 return req;
996 post:
997 return tevent_req_post(req, ev);
1000 static void cldap_netlogon_state_done(struct tevent_req *subreq)
1002 struct tevent_req *req = tevent_req_callback_data(subreq,
1003 struct tevent_req);
1004 struct cldap_netlogon_state *state = tevent_req_data(req,
1005 struct cldap_netlogon_state);
1006 NTSTATUS status;
1008 status = cldap_search_recv(subreq, state, &state->search);
1009 talloc_free(subreq);
1011 if (tevent_req_nterror(req, status)) {
1012 return;
1015 tevent_req_done(req);
1019 receive a cldap netlogon reply
1021 NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
1022 TALLOC_CTX *mem_ctx,
1023 struct cldap_netlogon *io)
1025 struct cldap_netlogon_state *state = tevent_req_data(req,
1026 struct cldap_netlogon_state);
1027 NTSTATUS status;
1028 DATA_BLOB *data;
1030 if (tevent_req_is_nterror(req, &status)) {
1031 goto failed;
1034 if (state->search.out.response == NULL) {
1035 status = NT_STATUS_NOT_FOUND;
1036 goto failed;
1039 if (state->search.out.response->num_attributes != 1 ||
1040 strcasecmp(state->search.out.response->attributes[0].name, "netlogon") != 0 ||
1041 state->search.out.response->attributes[0].num_values != 1 ||
1042 state->search.out.response->attributes[0].values->length < 2) {
1043 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1044 goto failed;
1046 data = state->search.out.response->attributes[0].values;
1048 status = pull_netlogon_samlogon_response(data, mem_ctx,
1049 &io->out.netlogon);
1050 if (!NT_STATUS_IS_OK(status)) {
1051 goto failed;
1054 if (io->in.map_response) {
1055 map_netlogon_samlogon_response(&io->out.netlogon);
1058 status = NT_STATUS_OK;
1059 failed:
1060 tevent_req_received(req);
1061 return status;
1065 sync cldap netlogon search
1067 NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
1068 TALLOC_CTX *mem_ctx,
1069 struct cldap_netlogon *io)
1071 TALLOC_CTX *frame;
1072 struct tevent_req *req;
1073 struct tevent_context *ev;
1074 NTSTATUS status;
1076 if (cldap->searches.list) {
1077 return NT_STATUS_PIPE_BUSY;
1080 if (cldap->incoming.handler) {
1081 return NT_STATUS_INVALID_PIPE_STATE;
1084 frame = talloc_stackframe();
1086 ev = samba_tevent_context_init(frame);
1087 if (ev == NULL) {
1088 TALLOC_FREE(frame);
1089 return NT_STATUS_NO_MEMORY;
1092 req = cldap_netlogon_send(mem_ctx, ev, cldap, io);
1093 if (req == NULL) {
1094 TALLOC_FREE(frame);
1095 return NT_STATUS_NO_MEMORY;
1098 if (!tevent_req_poll(req, ev)) {
1099 status = map_nt_error_from_unix_common(errno);
1100 TALLOC_FREE(frame);
1101 return status;
1104 status = cldap_netlogon_recv(req, mem_ctx, io);
1105 if (!NT_STATUS_IS_OK(status)) {
1106 TALLOC_FREE(frame);
1107 return status;
1110 TALLOC_FREE(frame);
1111 return NT_STATUS_OK;
1116 send an empty reply (used on any error, so the client doesn't keep waiting
1117 or send the bad request again)
1119 NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
1120 uint32_t message_id,
1121 struct tsocket_address *dest)
1123 NTSTATUS status;
1124 struct cldap_reply reply;
1125 struct ldap_Result result;
1127 reply.messageid = message_id;
1128 reply.dest = dest;
1129 reply.response = NULL;
1130 reply.result = &result;
1132 ZERO_STRUCT(result);
1134 status = cldap_reply_send(cldap, &reply);
1136 return status;
1140 send an error reply (used on any error, so the client doesn't keep waiting
1141 or send the bad request again)
1143 NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
1144 uint32_t message_id,
1145 struct tsocket_address *dest,
1146 int resultcode,
1147 const char *errormessage)
1149 NTSTATUS status;
1150 struct cldap_reply reply;
1151 struct ldap_Result result;
1153 reply.messageid = message_id;
1154 reply.dest = dest;
1155 reply.response = NULL;
1156 reply.result = &result;
1158 ZERO_STRUCT(result);
1159 result.resultcode = resultcode;
1160 result.errormessage = errormessage;
1162 status = cldap_reply_send(cldap, &reply);
1164 return status;
1169 send a netlogon reply
1171 NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
1172 uint32_t message_id,
1173 struct tsocket_address *dest,
1174 uint32_t version,
1175 struct netlogon_samlogon_response *netlogon)
1177 NTSTATUS status;
1178 struct cldap_reply reply;
1179 struct ldap_SearchResEntry response;
1180 struct ldap_Result result;
1181 TALLOC_CTX *tmp_ctx = talloc_new(cldap);
1182 DATA_BLOB blob;
1184 status = push_netlogon_samlogon_response(&blob, tmp_ctx,
1185 netlogon);
1186 if (!NT_STATUS_IS_OK(status)) {
1187 talloc_free(tmp_ctx);
1188 return status;
1190 reply.messageid = message_id;
1191 reply.dest = dest;
1192 reply.response = &response;
1193 reply.result = &result;
1195 ZERO_STRUCT(result);
1197 response.dn = "";
1198 response.num_attributes = 1;
1199 response.attributes = talloc(tmp_ctx, struct ldb_message_element);
1200 NT_STATUS_HAVE_NO_MEMORY(response.attributes);
1201 response.attributes->name = "netlogon";
1202 response.attributes->num_values = 1;
1203 response.attributes->values = &blob;
1205 status = cldap_reply_send(cldap, &reply);
1207 talloc_free(tmp_ctx);
1209 return status;