s3-registry: fix upgrade code
[Samba/gebeck_regimport.git] / libcli / cldap / cldap.c
blobb7df9d22835c850497ccdbdbb6a26d932dbaac33
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);
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 const struct tsocket_address *local_addr,
308 const struct tsocket_address *remote_addr,
309 struct cldap_socket **_cldap)
311 struct cldap_socket *c = NULL;
312 struct tsocket_address *any = NULL;
313 NTSTATUS status;
314 int ret;
315 const char *fam = NULL;
317 if (local_addr == NULL && remote_addr == NULL) {
318 return NT_STATUS_INVALID_PARAMETER_MIX;
321 if (remote_addr) {
322 bool is_ipv4;
323 bool is_ipv6;
325 is_ipv4 = tsocket_address_is_inet(remote_addr, "ipv4");
326 is_ipv6 = tsocket_address_is_inet(remote_addr, "ipv6");
328 if (is_ipv4) {
329 fam = "ipv4";
330 } else if (is_ipv6) {
331 fam = "ipv6";
332 } else {
333 return NT_STATUS_INVALID_ADDRESS;
337 c = talloc_zero(mem_ctx, struct cldap_socket);
338 if (!c) {
339 goto nomem;
342 if (!local_addr) {
344 * Here we know the address family of the remote address.
346 if (fam == NULL) {
347 return NT_STATUS_INVALID_PARAMETER_MIX;
350 ret = tsocket_address_inet_from_strings(c, fam,
351 NULL, 0,
352 &any);
353 if (ret != 0) {
354 status = map_nt_error_from_unix_common(errno);
355 goto nterror;
357 local_addr = any;
360 c->searches.idr = idr_init(c);
361 if (!c->searches.idr) {
362 goto nomem;
365 ret = tdgram_inet_udp_socket(local_addr, remote_addr,
366 c, &c->sock);
367 if (ret != 0) {
368 status = map_nt_error_from_unix_common(errno);
369 goto nterror;
371 talloc_free(any);
373 if (remote_addr) {
374 c->connected = true;
377 c->send_queue = tevent_queue_create(c, "cldap_send_queue");
378 if (!c->send_queue) {
379 goto nomem;
382 talloc_set_destructor(c, cldap_socket_destructor);
384 *_cldap = c;
385 return NT_STATUS_OK;
387 nomem:
388 status = NT_STATUS_NO_MEMORY;
389 nterror:
390 talloc_free(c);
391 return status;
395 setup a handler for incoming requests
397 NTSTATUS cldap_set_incoming_handler(struct cldap_socket *c,
398 struct tevent_context *ev,
399 void (*handler)(struct cldap_socket *,
400 void *private_data,
401 struct cldap_incoming *),
402 void *private_data)
404 if (c->connected) {
405 return NT_STATUS_PIPE_CONNECTED;
408 c->incoming.ev = ev;
409 c->incoming.handler = handler;
410 c->incoming.private_data = private_data;
412 if (!cldap_recvfrom_setup(c)) {
413 ZERO_STRUCT(c->incoming);
414 return NT_STATUS_NO_MEMORY;
417 return NT_STATUS_OK;
420 struct cldap_reply_state {
421 struct tsocket_address *dest;
422 DATA_BLOB blob;
425 static void cldap_reply_state_destroy(struct tevent_req *subreq);
428 queue a cldap reply for send
430 NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
432 struct cldap_reply_state *state = NULL;
433 struct ldap_message *msg;
434 DATA_BLOB blob1, blob2;
435 NTSTATUS status;
436 struct tevent_req *subreq;
438 if (cldap->connected) {
439 return NT_STATUS_PIPE_CONNECTED;
442 if (cldap->incoming.ev == NULL) {
443 return NT_STATUS_INVALID_PIPE_STATE;
446 if (!io->dest) {
447 return NT_STATUS_INVALID_ADDRESS;
450 state = talloc(cldap, struct cldap_reply_state);
451 NT_STATUS_HAVE_NO_MEMORY(state);
453 state->dest = tsocket_address_copy(io->dest, state);
454 if (!state->dest) {
455 goto nomem;
458 msg = talloc(state, struct ldap_message);
459 if (!msg) {
460 goto nomem;
463 msg->messageid = io->messageid;
464 msg->controls = NULL;
466 if (io->response) {
467 msg->type = LDAP_TAG_SearchResultEntry;
468 msg->r.SearchResultEntry = *io->response;
470 if (!ldap_encode(msg, NULL, &blob1, state)) {
471 status = NT_STATUS_INVALID_PARAMETER;
472 goto failed;
474 } else {
475 blob1 = data_blob(NULL, 0);
478 msg->type = LDAP_TAG_SearchResultDone;
479 msg->r.SearchResultDone = *io->result;
481 if (!ldap_encode(msg, NULL, &blob2, state)) {
482 status = NT_STATUS_INVALID_PARAMETER;
483 goto failed;
485 talloc_free(msg);
487 state->blob = data_blob_talloc(state, NULL, blob1.length + blob2.length);
488 if (!state->blob.data) {
489 goto nomem;
492 memcpy(state->blob.data, blob1.data, blob1.length);
493 memcpy(state->blob.data+blob1.length, blob2.data, blob2.length);
494 data_blob_free(&blob1);
495 data_blob_free(&blob2);
497 subreq = tdgram_sendto_queue_send(state,
498 cldap->incoming.ev,
499 cldap->sock,
500 cldap->send_queue,
501 state->blob.data,
502 state->blob.length,
503 state->dest);
504 if (!subreq) {
505 goto nomem;
507 /* the callback will just free the state, as we don't need a result */
508 tevent_req_set_callback(subreq, cldap_reply_state_destroy, state);
510 return NT_STATUS_OK;
512 nomem:
513 status = NT_STATUS_NO_MEMORY;
514 failed:
515 talloc_free(state);
516 return status;
519 static void cldap_reply_state_destroy(struct tevent_req *subreq)
521 struct cldap_reply_state *state = tevent_req_callback_data(subreq,
522 struct cldap_reply_state);
524 /* we don't want to know the result here, we just free the state */
525 talloc_free(subreq);
526 talloc_free(state);
529 static int cldap_search_state_destructor(struct cldap_search_state *s)
531 if (s->caller.cldap) {
532 if (s->message_id != -1) {
533 idr_remove(s->caller.cldap->searches.idr, s->message_id);
534 s->message_id = -1;
536 DLIST_REMOVE(s->caller.cldap->searches.list, s);
537 cldap_recvfrom_stop(s->caller.cldap);
538 ZERO_STRUCT(s->caller);
541 return 0;
544 static void cldap_search_state_queue_done(struct tevent_req *subreq);
545 static void cldap_search_state_wakeup_done(struct tevent_req *subreq);
548 queue a cldap reply for send
550 struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
551 struct tevent_context *ev,
552 struct cldap_socket *cldap,
553 const struct cldap_search *io)
555 struct tevent_req *req, *subreq;
556 struct cldap_search_state *state = NULL;
557 struct ldap_message *msg;
558 struct ldap_SearchRequest *search;
559 struct timeval now;
560 struct timeval end;
561 uint32_t i;
562 int ret;
564 req = tevent_req_create(mem_ctx, &state,
565 struct cldap_search_state);
566 if (!req) {
567 return NULL;
569 ZERO_STRUCTP(state);
570 state->caller.ev = ev;
571 state->req = req;
572 state->caller.cldap = cldap;
573 state->message_id = -1;
575 talloc_set_destructor(state, cldap_search_state_destructor);
577 if (io->in.dest_address) {
578 if (cldap->connected) {
579 tevent_req_nterror(req, NT_STATUS_PIPE_CONNECTED);
580 goto post;
582 ret = tsocket_address_inet_from_strings(state,
583 "ip",
584 io->in.dest_address,
585 io->in.dest_port,
586 &state->request.dest);
587 if (ret != 0) {
588 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
589 goto post;
591 } else {
592 if (!cldap->connected) {
593 tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
594 goto post;
596 state->request.dest = NULL;
599 state->message_id = idr_get_new_random(cldap->searches.idr,
600 state, UINT16_MAX);
601 if (state->message_id == -1) {
602 tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
603 goto post;
606 msg = talloc(state, struct ldap_message);
607 if (tevent_req_nomem(msg, req)) {
608 goto post;
611 msg->messageid = state->message_id;
612 msg->type = LDAP_TAG_SearchRequest;
613 msg->controls = NULL;
614 search = &msg->r.SearchRequest;
616 search->basedn = "";
617 search->scope = LDAP_SEARCH_SCOPE_BASE;
618 search->deref = LDAP_DEREFERENCE_NEVER;
619 search->timelimit = 0;
620 search->sizelimit = 0;
621 search->attributesonly = false;
622 search->num_attributes = str_list_length(io->in.attributes);
623 search->attributes = io->in.attributes;
624 search->tree = ldb_parse_tree(msg, io->in.filter);
625 if (tevent_req_nomem(search->tree, req)) {
626 goto post;
629 if (!ldap_encode(msg, NULL, &state->request.blob, state)) {
630 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
631 goto post;
633 talloc_free(msg);
635 state->request.idx = 0;
636 state->request.delay = 10*1000*1000;
637 state->request.count = 3;
638 if (io->in.timeout > 0) {
639 state->request.delay = io->in.timeout * 1000 * 1000;
640 state->request.count = io->in.retries + 1;
643 now = tevent_timeval_current();
644 end = now;
645 for (i = 0; i < state->request.count; i++) {
646 end = tevent_timeval_add(&end, state->request.delay / 1000000,
647 state->request.delay % 1000000);
650 if (!tevent_req_set_endtime(req, state->caller.ev, end)) {
651 tevent_req_oom(req);
652 goto post;
655 subreq = tdgram_sendto_queue_send(state,
656 state->caller.ev,
657 state->caller.cldap->sock,
658 state->caller.cldap->send_queue,
659 state->request.blob.data,
660 state->request.blob.length,
661 state->request.dest);
662 if (tevent_req_nomem(subreq, req)) {
663 goto post;
665 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
667 DLIST_ADD_END(cldap->searches.list, state, struct cldap_search_state *);
669 return req;
671 post:
672 return tevent_req_post(req, state->caller.ev);
675 static void cldap_search_state_queue_done(struct tevent_req *subreq)
677 struct tevent_req *req = tevent_req_callback_data(subreq,
678 struct tevent_req);
679 struct cldap_search_state *state = tevent_req_data(req,
680 struct cldap_search_state);
681 ssize_t ret;
682 int sys_errno = 0;
683 struct timeval next;
685 ret = tdgram_sendto_queue_recv(subreq, &sys_errno);
686 talloc_free(subreq);
687 if (ret == -1) {
688 NTSTATUS status;
689 status = map_nt_error_from_unix_common(sys_errno);
690 DLIST_REMOVE(state->caller.cldap->searches.list, state);
691 ZERO_STRUCT(state->caller.cldap);
692 tevent_req_nterror(req, status);
693 return;
696 state->request.idx++;
698 /* wait for incoming traffic */
699 if (!cldap_recvfrom_setup(state->caller.cldap)) {
700 tevent_req_oom(req);
701 return;
704 if (state->request.idx > state->request.count) {
705 /* we just wait for the response or a timeout */
706 return;
709 next = tevent_timeval_current_ofs(state->request.delay / 1000000,
710 state->request.delay % 1000000);
711 subreq = tevent_wakeup_send(state,
712 state->caller.ev,
713 next);
714 if (tevent_req_nomem(subreq, req)) {
715 return;
717 tevent_req_set_callback(subreq, cldap_search_state_wakeup_done, req);
720 static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
722 struct tevent_req *req = tevent_req_callback_data(subreq,
723 struct tevent_req);
724 struct cldap_search_state *state = tevent_req_data(req,
725 struct cldap_search_state);
726 bool ok;
728 ok = tevent_wakeup_recv(subreq);
729 talloc_free(subreq);
730 if (!ok) {
731 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
732 return;
735 subreq = tdgram_sendto_queue_send(state,
736 state->caller.ev,
737 state->caller.cldap->sock,
738 state->caller.cldap->send_queue,
739 state->request.blob.data,
740 state->request.blob.length,
741 state->request.dest);
742 if (tevent_req_nomem(subreq, req)) {
743 return;
745 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
749 receive a cldap reply
751 NTSTATUS cldap_search_recv(struct tevent_req *req,
752 TALLOC_CTX *mem_ctx,
753 struct cldap_search *io)
755 struct cldap_search_state *state = tevent_req_data(req,
756 struct cldap_search_state);
757 struct ldap_message *ldap_msg;
758 NTSTATUS status;
760 if (tevent_req_is_nterror(req, &status)) {
761 goto failed;
764 ldap_msg = talloc(mem_ctx, struct ldap_message);
765 if (!ldap_msg) {
766 goto nomem;
769 status = ldap_decode(state->response.asn1, NULL, ldap_msg);
770 if (!NT_STATUS_IS_OK(status)) {
771 goto failed;
774 ZERO_STRUCT(io->out);
776 /* the first possible form has a search result in first place */
777 if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
778 io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
779 if (!io->out.response) {
780 goto nomem;
782 *io->out.response = ldap_msg->r.SearchResultEntry;
784 /* decode the 2nd part */
785 status = ldap_decode(state->response.asn1, NULL, ldap_msg);
786 if (!NT_STATUS_IS_OK(status)) {
787 goto failed;
791 if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
792 status = NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
793 goto failed;
796 io->out.result = talloc(mem_ctx, struct ldap_Result);
797 if (!io->out.result) {
798 goto nomem;
800 *io->out.result = ldap_msg->r.SearchResultDone;
802 if (io->out.result->resultcode != LDAP_SUCCESS) {
803 status = NT_STATUS_LDAP(io->out.result->resultcode);
804 goto failed;
807 tevent_req_received(req);
808 return NT_STATUS_OK;
810 nomem:
811 status = NT_STATUS_NO_MEMORY;
812 failed:
813 tevent_req_received(req);
814 return status;
819 synchronous cldap search
821 NTSTATUS cldap_search(struct cldap_socket *cldap,
822 TALLOC_CTX *mem_ctx,
823 struct cldap_search *io)
825 TALLOC_CTX *frame;
826 struct tevent_req *req;
827 struct tevent_context *ev;
828 NTSTATUS status;
830 if (cldap->searches.list) {
831 return NT_STATUS_PIPE_BUSY;
834 if (cldap->incoming.handler) {
835 return NT_STATUS_INVALID_PIPE_STATE;
838 frame = talloc_stackframe();
840 ev = tevent_context_init(frame);
841 if (ev == NULL) {
842 TALLOC_FREE(frame);
843 return NT_STATUS_NO_MEMORY;
846 req = cldap_search_send(mem_ctx, ev, cldap, io);
847 if (req == NULL) {
848 TALLOC_FREE(frame);
849 return NT_STATUS_NO_MEMORY;
852 if (!tevent_req_poll(req, ev)) {
853 status = map_nt_error_from_unix_common(errno);
854 TALLOC_FREE(frame);
855 return status;
858 status = cldap_search_recv(req, mem_ctx, io);
859 if (!NT_STATUS_IS_OK(status)) {
860 TALLOC_FREE(frame);
861 return status;
864 TALLOC_FREE(frame);
865 return NT_STATUS_OK;
868 struct cldap_netlogon_state {
869 struct cldap_search search;
872 static void cldap_netlogon_state_done(struct tevent_req *subreq);
874 queue a cldap netlogon for send
876 struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
877 struct tevent_context *ev,
878 struct cldap_socket *cldap,
879 const struct cldap_netlogon *io)
881 struct tevent_req *req, *subreq;
882 struct cldap_netlogon_state *state;
883 char *filter;
884 static const char * const attr[] = { "NetLogon", NULL };
886 req = tevent_req_create(mem_ctx, &state,
887 struct cldap_netlogon_state);
888 if (!req) {
889 return NULL;
892 filter = talloc_asprintf(state, "(&(NtVer=%s)",
893 ldap_encode_ndr_uint32(state, io->in.version));
894 if (tevent_req_nomem(filter, req)) {
895 goto post;
897 if (io->in.user) {
898 filter = talloc_asprintf_append_buffer(filter, "(User=%s)", io->in.user);
899 if (tevent_req_nomem(filter, req)) {
900 goto post;
903 if (io->in.host) {
904 filter = talloc_asprintf_append_buffer(filter, "(Host=%s)", io->in.host);
905 if (tevent_req_nomem(filter, req)) {
906 goto post;
909 if (io->in.realm) {
910 filter = talloc_asprintf_append_buffer(filter, "(DnsDomain=%s)", io->in.realm);
911 if (tevent_req_nomem(filter, req)) {
912 goto post;
915 if (io->in.acct_control != -1) {
916 filter = talloc_asprintf_append_buffer(filter, "(AAC=%s)",
917 ldap_encode_ndr_uint32(state, io->in.acct_control));
918 if (tevent_req_nomem(filter, req)) {
919 goto post;
922 if (io->in.domain_sid) {
923 struct dom_sid *sid = dom_sid_parse_talloc(state, io->in.domain_sid);
924 if (tevent_req_nomem(sid, req)) {
925 goto post;
927 filter = talloc_asprintf_append_buffer(filter, "(domainSid=%s)",
928 ldap_encode_ndr_dom_sid(state, sid));
929 if (tevent_req_nomem(filter, req)) {
930 goto post;
933 if (io->in.domain_guid) {
934 struct GUID guid;
935 NTSTATUS status;
936 status = GUID_from_string(io->in.domain_guid, &guid);
937 if (tevent_req_nterror(req, status)) {
938 goto post;
940 filter = talloc_asprintf_append_buffer(filter, "(DomainGuid=%s)",
941 ldap_encode_ndr_GUID(state, &guid));
942 if (tevent_req_nomem(filter, req)) {
943 goto post;
946 filter = talloc_asprintf_append_buffer(filter, ")");
947 if (tevent_req_nomem(filter, req)) {
948 goto post;
951 if (io->in.dest_address) {
952 state->search.in.dest_address = talloc_strdup(state,
953 io->in.dest_address);
954 if (tevent_req_nomem(state->search.in.dest_address, req)) {
955 goto post;
957 state->search.in.dest_port = io->in.dest_port;
958 } else {
959 state->search.in.dest_address = NULL;
960 state->search.in.dest_port = 0;
962 state->search.in.filter = filter;
963 state->search.in.attributes = attr;
964 state->search.in.timeout = 2;
965 state->search.in.retries = 2;
967 subreq = cldap_search_send(state, ev, cldap, &state->search);
968 if (tevent_req_nomem(subreq, req)) {
969 goto post;
971 tevent_req_set_callback(subreq, cldap_netlogon_state_done, req);
973 return req;
974 post:
975 return tevent_req_post(req, ev);
978 static void cldap_netlogon_state_done(struct tevent_req *subreq)
980 struct tevent_req *req = tevent_req_callback_data(subreq,
981 struct tevent_req);
982 struct cldap_netlogon_state *state = tevent_req_data(req,
983 struct cldap_netlogon_state);
984 NTSTATUS status;
986 status = cldap_search_recv(subreq, state, &state->search);
987 talloc_free(subreq);
989 if (tevent_req_nterror(req, status)) {
990 return;
993 tevent_req_done(req);
997 receive a cldap netlogon reply
999 NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
1000 TALLOC_CTX *mem_ctx,
1001 struct cldap_netlogon *io)
1003 struct cldap_netlogon_state *state = tevent_req_data(req,
1004 struct cldap_netlogon_state);
1005 NTSTATUS status;
1006 DATA_BLOB *data;
1008 if (tevent_req_is_nterror(req, &status)) {
1009 goto failed;
1012 if (state->search.out.response == NULL) {
1013 status = NT_STATUS_NOT_FOUND;
1014 goto failed;
1017 if (state->search.out.response->num_attributes != 1 ||
1018 strcasecmp(state->search.out.response->attributes[0].name, "netlogon") != 0 ||
1019 state->search.out.response->attributes[0].num_values != 1 ||
1020 state->search.out.response->attributes[0].values->length < 2) {
1021 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1022 goto failed;
1024 data = state->search.out.response->attributes[0].values;
1026 status = pull_netlogon_samlogon_response(data, mem_ctx,
1027 &io->out.netlogon);
1028 if (!NT_STATUS_IS_OK(status)) {
1029 goto failed;
1032 if (io->in.map_response) {
1033 map_netlogon_samlogon_response(&io->out.netlogon);
1036 status = NT_STATUS_OK;
1037 failed:
1038 tevent_req_received(req);
1039 return status;
1043 sync cldap netlogon search
1045 NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
1046 TALLOC_CTX *mem_ctx,
1047 struct cldap_netlogon *io)
1049 TALLOC_CTX *frame;
1050 struct tevent_req *req;
1051 struct tevent_context *ev;
1052 NTSTATUS status;
1054 if (cldap->searches.list) {
1055 return NT_STATUS_PIPE_BUSY;
1058 if (cldap->incoming.handler) {
1059 return NT_STATUS_INVALID_PIPE_STATE;
1062 frame = talloc_stackframe();
1064 ev = tevent_context_init(frame);
1065 if (ev == NULL) {
1066 TALLOC_FREE(frame);
1067 return NT_STATUS_NO_MEMORY;
1070 req = cldap_netlogon_send(mem_ctx, ev, cldap, io);
1071 if (req == NULL) {
1072 TALLOC_FREE(frame);
1073 return NT_STATUS_NO_MEMORY;
1076 if (!tevent_req_poll(req, ev)) {
1077 status = map_nt_error_from_unix_common(errno);
1078 TALLOC_FREE(frame);
1079 return status;
1082 status = cldap_netlogon_recv(req, mem_ctx, io);
1083 if (!NT_STATUS_IS_OK(status)) {
1084 TALLOC_FREE(frame);
1085 return status;
1088 TALLOC_FREE(frame);
1089 return NT_STATUS_OK;
1094 send an empty reply (used on any error, so the client doesn't keep waiting
1095 or send the bad request again)
1097 NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
1098 uint32_t message_id,
1099 struct tsocket_address *dest)
1101 NTSTATUS status;
1102 struct cldap_reply reply;
1103 struct ldap_Result result;
1105 reply.messageid = message_id;
1106 reply.dest = dest;
1107 reply.response = NULL;
1108 reply.result = &result;
1110 ZERO_STRUCT(result);
1112 status = cldap_reply_send(cldap, &reply);
1114 return status;
1118 send an error reply (used on any error, so the client doesn't keep waiting
1119 or send the bad request again)
1121 NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
1122 uint32_t message_id,
1123 struct tsocket_address *dest,
1124 int resultcode,
1125 const char *errormessage)
1127 NTSTATUS status;
1128 struct cldap_reply reply;
1129 struct ldap_Result result;
1131 reply.messageid = message_id;
1132 reply.dest = dest;
1133 reply.response = NULL;
1134 reply.result = &result;
1136 ZERO_STRUCT(result);
1137 result.resultcode = resultcode;
1138 result.errormessage = errormessage;
1140 status = cldap_reply_send(cldap, &reply);
1142 return status;
1147 send a netlogon reply
1149 NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
1150 uint32_t message_id,
1151 struct tsocket_address *dest,
1152 uint32_t version,
1153 struct netlogon_samlogon_response *netlogon)
1155 NTSTATUS status;
1156 struct cldap_reply reply;
1157 struct ldap_SearchResEntry response;
1158 struct ldap_Result result;
1159 TALLOC_CTX *tmp_ctx = talloc_new(cldap);
1160 DATA_BLOB blob;
1162 status = push_netlogon_samlogon_response(&blob, tmp_ctx,
1163 netlogon);
1164 if (!NT_STATUS_IS_OK(status)) {
1165 talloc_free(tmp_ctx);
1166 return status;
1168 reply.messageid = message_id;
1169 reply.dest = dest;
1170 reply.response = &response;
1171 reply.result = &result;
1173 ZERO_STRUCT(result);
1175 response.dn = "";
1176 response.num_attributes = 1;
1177 response.attributes = talloc(tmp_ctx, struct ldb_message_element);
1178 NT_STATUS_HAVE_NO_MEMORY(response.attributes);
1179 response.attributes->name = "netlogon";
1180 response.attributes->num_values = 1;
1181 response.attributes->values = &blob;
1183 status = cldap_reply_send(cldap, &reply);
1185 talloc_free(tmp_ctx);
1187 return status;