s3: smbd: remove redundant smb_dname arg from dptr_create()
[Samba.git] / libcli / cldap / cldap.c
blobf609bf278e4b09610ef79be208d6b8c9bca8cbbd
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 /* this shouldn't happen but should be protected against */
145 if (c->searches.list == NULL) {
146 return false;
148 ev = c->searches.list->caller.ev;
151 c->recv_subreq = tdgram_recvfrom_send(c, ev, c->sock);
152 if (!c->recv_subreq) {
153 return false;
155 tevent_req_set_callback(c->recv_subreq, cldap_recvfrom_done, c);
157 return true;
160 static void cldap_recvfrom_stop(struct cldap_socket *c)
162 if (!c->recv_subreq) {
163 return;
166 if (c->searches.list || c->incoming.handler) {
167 return;
170 talloc_free(c->recv_subreq);
171 c->recv_subreq = NULL;
174 static bool cldap_socket_recv_dgram(struct cldap_socket *c,
175 struct cldap_incoming *in);
177 static void cldap_recvfrom_done(struct tevent_req *subreq)
179 struct cldap_socket *c = tevent_req_callback_data(subreq,
180 struct cldap_socket);
181 struct cldap_incoming *in = NULL;
182 ssize_t ret;
183 bool setup_done;
185 c->recv_subreq = NULL;
187 in = talloc_zero(c, struct cldap_incoming);
188 if (!in) {
189 goto nomem;
192 ret = tdgram_recvfrom_recv(subreq,
193 &in->recv_errno,
195 &in->buf,
196 &in->src);
197 talloc_free(subreq);
198 subreq = NULL;
199 if (ret >= 0) {
200 in->len = ret;
202 if (ret == -1 && in->recv_errno == 0) {
203 in->recv_errno = EIO;
206 /* this function should free or steal 'in' */
207 setup_done = cldap_socket_recv_dgram(c, in);
208 in = NULL;
210 if (!setup_done && !cldap_recvfrom_setup(c)) {
211 goto nomem;
214 return;
216 nomem:
217 talloc_free(subreq);
218 talloc_free(in);
222 handle recv events on a cldap socket
224 static bool cldap_socket_recv_dgram(struct cldap_socket *c,
225 struct cldap_incoming *in)
227 struct asn1_data *asn1;
228 void *p;
229 struct cldap_search_state *search;
230 NTSTATUS status;
232 if (in->recv_errno != 0) {
233 goto error;
236 asn1 = asn1_init(in);
237 if (!asn1) {
238 goto nomem;
241 asn1_load_nocopy(asn1, in->buf, in->len);
243 in->ldap_msg = talloc(in, struct ldap_message);
244 if (in->ldap_msg == NULL) {
245 goto nomem;
248 /* this initial decode is used to find the message id */
249 status = ldap_decode(asn1, NULL, in->ldap_msg);
250 if (!NT_STATUS_IS_OK(status)) {
251 goto nterror;
254 /* find the pending request */
255 p = idr_find(c->searches.idr, in->ldap_msg->messageid);
256 if (p == NULL) {
257 if (!c->incoming.handler) {
258 TALLOC_FREE(in);
259 return true;
262 /* this function should free or steal 'in' */
263 c->incoming.handler(c, c->incoming.private_data, in);
264 return false;
267 search = talloc_get_type_abort(p, struct cldap_search_state);
268 search->response.in = talloc_move(search, &in);
270 search->response.asn1 = asn1;
272 asn1_load_nocopy(search->response.asn1,
273 search->response.in->buf, search->response.in->len);
275 DLIST_REMOVE(c->searches.list, search);
277 if (cldap_recvfrom_setup(c)) {
278 tevent_req_done(search->req);
279 return true;
283 * This request was ok, just defer the notify of the caller
284 * and then just fail the next request if needed
286 tevent_req_defer_callback(search->req, search->caller.ev);
287 tevent_req_done(search->req);
289 status = NT_STATUS_NO_MEMORY;
290 /* in is NULL it this point */
291 goto nterror;
292 nomem:
293 in->recv_errno = ENOMEM;
294 error:
295 status = map_nt_error_from_unix_common(in->recv_errno);
296 nterror:
297 TALLOC_FREE(in);
298 /* in connected mode the first pending search gets the error */
299 if (!c->connected) {
300 /* otherwise we just ignore the error */
301 return false;
303 if (!c->searches.list) {
304 return false;
307 * We might called tevent_req_done() for a successful
308 * search before, so we better deliver the failure
309 * after the success, that is why we better also
310 * use tevent_req_defer_callback() here.
312 tevent_req_defer_callback(c->searches.list->req,
313 c->searches.list->caller.ev);
314 tevent_req_nterror(c->searches.list->req, status);
315 return false;
319 initialise a cldap_sock
321 NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx,
322 const struct tsocket_address *local_addr,
323 const struct tsocket_address *remote_addr,
324 struct cldap_socket **_cldap)
326 struct cldap_socket *c = NULL;
327 struct tsocket_address *any = NULL;
328 NTSTATUS status;
329 int ret;
330 const char *fam = NULL;
332 if (local_addr == NULL && remote_addr == NULL) {
333 return NT_STATUS_INVALID_PARAMETER_MIX;
336 if (remote_addr) {
337 bool is_ipv4;
338 bool is_ipv6;
340 is_ipv4 = tsocket_address_is_inet(remote_addr, "ipv4");
341 is_ipv6 = tsocket_address_is_inet(remote_addr, "ipv6");
343 if (is_ipv4) {
344 fam = "ipv4";
345 } else if (is_ipv6) {
346 fam = "ipv6";
347 } else {
348 return NT_STATUS_INVALID_ADDRESS;
352 c = talloc_zero(mem_ctx, struct cldap_socket);
353 if (!c) {
354 goto nomem;
357 if (!local_addr) {
359 * Here we know the address family of the remote address.
361 if (fam == NULL) {
362 return NT_STATUS_INVALID_PARAMETER_MIX;
365 ret = tsocket_address_inet_from_strings(c, fam,
366 NULL, 0,
367 &any);
368 if (ret != 0) {
369 status = map_nt_error_from_unix_common(errno);
370 goto nterror;
372 local_addr = any;
375 c->searches.idr = idr_init(c);
376 if (!c->searches.idr) {
377 goto nomem;
380 ret = tdgram_inet_udp_socket(local_addr, remote_addr,
381 c, &c->sock);
382 if (ret != 0) {
383 status = map_nt_error_from_unix_common(errno);
384 goto nterror;
386 talloc_free(any);
388 if (remote_addr) {
389 c->connected = true;
392 c->send_queue = tevent_queue_create(c, "cldap_send_queue");
393 if (!c->send_queue) {
394 goto nomem;
397 talloc_set_destructor(c, cldap_socket_destructor);
399 *_cldap = c;
400 return NT_STATUS_OK;
402 nomem:
403 status = NT_STATUS_NO_MEMORY;
404 nterror:
405 talloc_free(c);
406 return status;
410 setup a handler for incoming requests
412 NTSTATUS cldap_set_incoming_handler(struct cldap_socket *c,
413 struct tevent_context *ev,
414 void (*handler)(struct cldap_socket *,
415 void *private_data,
416 struct cldap_incoming *),
417 void *private_data)
419 if (c->connected) {
420 return NT_STATUS_PIPE_CONNECTED;
423 c->incoming.ev = ev;
424 c->incoming.handler = handler;
425 c->incoming.private_data = private_data;
427 if (!cldap_recvfrom_setup(c)) {
428 ZERO_STRUCT(c->incoming);
429 return NT_STATUS_NO_MEMORY;
432 return NT_STATUS_OK;
435 struct cldap_reply_state {
436 struct tsocket_address *dest;
437 DATA_BLOB blob;
440 static void cldap_reply_state_destroy(struct tevent_req *subreq);
443 queue a cldap reply for send
445 NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
447 struct cldap_reply_state *state = NULL;
448 struct ldap_message *msg;
449 DATA_BLOB blob1, blob2;
450 NTSTATUS status;
451 struct tevent_req *subreq;
453 if (cldap->connected) {
454 return NT_STATUS_PIPE_CONNECTED;
457 if (cldap->incoming.ev == NULL) {
458 return NT_STATUS_INVALID_PIPE_STATE;
461 if (!io->dest) {
462 return NT_STATUS_INVALID_ADDRESS;
465 state = talloc(cldap, struct cldap_reply_state);
466 NT_STATUS_HAVE_NO_MEMORY(state);
468 state->dest = tsocket_address_copy(io->dest, state);
469 if (!state->dest) {
470 goto nomem;
473 msg = talloc(state, struct ldap_message);
474 if (!msg) {
475 goto nomem;
478 msg->messageid = io->messageid;
479 msg->controls = NULL;
481 if (io->response) {
482 msg->type = LDAP_TAG_SearchResultEntry;
483 msg->r.SearchResultEntry = *io->response;
485 if (!ldap_encode(msg, NULL, &blob1, state)) {
486 status = NT_STATUS_INVALID_PARAMETER;
487 goto failed;
489 } else {
490 blob1 = data_blob(NULL, 0);
493 msg->type = LDAP_TAG_SearchResultDone;
494 msg->r.SearchResultDone = *io->result;
496 if (!ldap_encode(msg, NULL, &blob2, state)) {
497 status = NT_STATUS_INVALID_PARAMETER;
498 goto failed;
500 talloc_free(msg);
502 state->blob = data_blob_talloc(state, NULL, blob1.length + blob2.length);
503 if (!state->blob.data) {
504 goto nomem;
507 memcpy(state->blob.data, blob1.data, blob1.length);
508 memcpy(state->blob.data+blob1.length, blob2.data, blob2.length);
509 data_blob_free(&blob1);
510 data_blob_free(&blob2);
512 subreq = tdgram_sendto_queue_send(state,
513 cldap->incoming.ev,
514 cldap->sock,
515 cldap->send_queue,
516 state->blob.data,
517 state->blob.length,
518 state->dest);
519 if (!subreq) {
520 goto nomem;
522 /* the callback will just free the state, as we don't need a result */
523 tevent_req_set_callback(subreq, cldap_reply_state_destroy, state);
525 return NT_STATUS_OK;
527 nomem:
528 status = NT_STATUS_NO_MEMORY;
529 failed:
530 talloc_free(state);
531 return status;
534 static void cldap_reply_state_destroy(struct tevent_req *subreq)
536 struct cldap_reply_state *state = tevent_req_callback_data(subreq,
537 struct cldap_reply_state);
539 /* we don't want to know the result here, we just free the state */
540 talloc_free(subreq);
541 talloc_free(state);
544 static int cldap_search_state_destructor(struct cldap_search_state *s)
546 if (s->caller.cldap) {
547 if (s->message_id != -1) {
548 idr_remove(s->caller.cldap->searches.idr, s->message_id);
549 s->message_id = -1;
551 DLIST_REMOVE(s->caller.cldap->searches.list, s);
552 cldap_recvfrom_stop(s->caller.cldap);
553 ZERO_STRUCT(s->caller);
556 return 0;
559 static void cldap_search_state_queue_done(struct tevent_req *subreq);
560 static void cldap_search_state_wakeup_done(struct tevent_req *subreq);
563 queue a cldap reply for send
565 struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
566 struct tevent_context *ev,
567 struct cldap_socket *cldap,
568 const struct cldap_search *io)
570 struct tevent_req *req, *subreq;
571 struct cldap_search_state *state = NULL;
572 struct ldap_message *msg;
573 struct ldap_SearchRequest *search;
574 struct timeval now;
575 struct timeval end;
576 uint32_t i;
577 int ret;
579 req = tevent_req_create(mem_ctx, &state,
580 struct cldap_search_state);
581 if (!req) {
582 return NULL;
584 state->caller.ev = ev;
585 state->req = req;
586 state->caller.cldap = cldap;
587 state->message_id = -1;
589 talloc_set_destructor(state, cldap_search_state_destructor);
591 if (state->caller.cldap == NULL) {
592 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
593 goto post;
596 if (io->in.dest_address) {
597 if (cldap->connected) {
598 tevent_req_nterror(req, NT_STATUS_PIPE_CONNECTED);
599 goto post;
601 ret = tsocket_address_inet_from_strings(state,
602 "ip",
603 io->in.dest_address,
604 io->in.dest_port,
605 &state->request.dest);
606 if (ret != 0) {
607 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
608 goto post;
610 } else {
611 if (!cldap->connected) {
612 tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
613 goto post;
615 state->request.dest = NULL;
618 state->message_id = idr_get_new_random(cldap->searches.idr,
619 state, UINT16_MAX);
620 if (state->message_id == -1) {
621 tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
622 goto post;
625 msg = talloc(state, struct ldap_message);
626 if (tevent_req_nomem(msg, req)) {
627 goto post;
630 msg->messageid = state->message_id;
631 msg->type = LDAP_TAG_SearchRequest;
632 msg->controls = NULL;
633 search = &msg->r.SearchRequest;
635 search->basedn = "";
636 search->scope = LDAP_SEARCH_SCOPE_BASE;
637 search->deref = LDAP_DEREFERENCE_NEVER;
638 search->timelimit = 0;
639 search->sizelimit = 0;
640 search->attributesonly = false;
641 search->num_attributes = str_list_length(io->in.attributes);
642 search->attributes = io->in.attributes;
643 search->tree = ldb_parse_tree(msg, io->in.filter);
644 if (tevent_req_nomem(search->tree, req)) {
645 goto post;
648 if (!ldap_encode(msg, NULL, &state->request.blob, state)) {
649 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
650 goto post;
652 talloc_free(msg);
654 state->request.idx = 0;
655 state->request.delay = 10*1000*1000;
656 state->request.count = 3;
657 if (io->in.timeout > 0) {
658 state->request.delay = io->in.timeout * 1000 * 1000;
659 state->request.count = io->in.retries + 1;
662 now = tevent_timeval_current();
663 end = now;
664 for (i = 0; i < state->request.count; i++) {
665 end = tevent_timeval_add(&end, state->request.delay / 1000000,
666 state->request.delay % 1000000);
669 if (!tevent_req_set_endtime(req, state->caller.ev, end)) {
670 goto post;
673 subreq = tdgram_sendto_queue_send(state,
674 state->caller.ev,
675 state->caller.cldap->sock,
676 state->caller.cldap->send_queue,
677 state->request.blob.data,
678 state->request.blob.length,
679 state->request.dest);
680 if (tevent_req_nomem(subreq, req)) {
681 goto post;
683 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
685 DLIST_ADD_END(cldap->searches.list, state);
687 return req;
689 post:
690 return tevent_req_post(req, state->caller.ev);
693 static void cldap_search_state_queue_done(struct tevent_req *subreq)
695 struct tevent_req *req = tevent_req_callback_data(subreq,
696 struct tevent_req);
697 struct cldap_search_state *state = tevent_req_data(req,
698 struct cldap_search_state);
699 ssize_t ret;
700 int sys_errno = 0;
701 struct timeval next;
703 ret = tdgram_sendto_queue_recv(subreq, &sys_errno);
704 talloc_free(subreq);
705 if (ret == -1) {
706 NTSTATUS status;
707 status = map_nt_error_from_unix_common(sys_errno);
708 DLIST_REMOVE(state->caller.cldap->searches.list, state);
709 ZERO_STRUCT(state->caller.cldap);
710 tevent_req_nterror(req, status);
711 return;
714 state->request.idx++;
716 /* wait for incoming traffic */
717 if (!cldap_recvfrom_setup(state->caller.cldap)) {
718 tevent_req_oom(req);
719 return;
722 if (state->request.idx > state->request.count) {
723 /* we just wait for the response or a timeout */
724 return;
727 next = tevent_timeval_current_ofs(state->request.delay / 1000000,
728 state->request.delay % 1000000);
729 subreq = tevent_wakeup_send(state,
730 state->caller.ev,
731 next);
732 if (tevent_req_nomem(subreq, req)) {
733 return;
735 tevent_req_set_callback(subreq, cldap_search_state_wakeup_done, req);
738 static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
740 struct tevent_req *req = tevent_req_callback_data(subreq,
741 struct tevent_req);
742 struct cldap_search_state *state = tevent_req_data(req,
743 struct cldap_search_state);
744 bool ok;
746 ok = tevent_wakeup_recv(subreq);
747 talloc_free(subreq);
748 if (!ok) {
749 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
750 return;
753 subreq = tdgram_sendto_queue_send(state,
754 state->caller.ev,
755 state->caller.cldap->sock,
756 state->caller.cldap->send_queue,
757 state->request.blob.data,
758 state->request.blob.length,
759 state->request.dest);
760 if (tevent_req_nomem(subreq, req)) {
761 return;
763 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
767 receive a cldap reply
769 NTSTATUS cldap_search_recv(struct tevent_req *req,
770 TALLOC_CTX *mem_ctx,
771 struct cldap_search *io)
773 struct cldap_search_state *state = tevent_req_data(req,
774 struct cldap_search_state);
775 struct ldap_message *ldap_msg;
776 NTSTATUS status;
778 if (tevent_req_is_nterror(req, &status)) {
779 goto failed;
782 ldap_msg = talloc(mem_ctx, struct ldap_message);
783 if (!ldap_msg) {
784 goto nomem;
787 status = ldap_decode(state->response.asn1, NULL, ldap_msg);
788 if (!NT_STATUS_IS_OK(status)) {
789 goto failed;
792 ZERO_STRUCT(io->out);
794 /* the first possible form has a search result in first place */
795 if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
796 io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
797 if (!io->out.response) {
798 goto nomem;
800 *io->out.response = ldap_msg->r.SearchResultEntry;
802 /* decode the 2nd part */
803 status = ldap_decode(state->response.asn1, NULL, ldap_msg);
804 if (!NT_STATUS_IS_OK(status)) {
805 goto failed;
809 if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
810 status = NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
811 goto failed;
814 io->out.result = talloc(mem_ctx, struct ldap_Result);
815 if (!io->out.result) {
816 goto nomem;
818 *io->out.result = ldap_msg->r.SearchResultDone;
820 if (io->out.result->resultcode != LDAP_SUCCESS) {
821 status = NT_STATUS_LDAP(io->out.result->resultcode);
822 goto failed;
825 tevent_req_received(req);
826 return NT_STATUS_OK;
828 nomem:
829 status = NT_STATUS_NO_MEMORY;
830 failed:
831 tevent_req_received(req);
832 return status;
837 synchronous cldap search
839 NTSTATUS cldap_search(struct cldap_socket *cldap,
840 TALLOC_CTX *mem_ctx,
841 struct cldap_search *io)
843 TALLOC_CTX *frame;
844 struct tevent_req *req;
845 struct tevent_context *ev;
846 NTSTATUS status;
848 if (cldap->searches.list) {
849 return NT_STATUS_PIPE_BUSY;
852 if (cldap->incoming.handler) {
853 return NT_STATUS_INVALID_PIPE_STATE;
856 frame = talloc_stackframe();
858 ev = samba_tevent_context_init(frame);
859 if (ev == NULL) {
860 TALLOC_FREE(frame);
861 return NT_STATUS_NO_MEMORY;
864 req = cldap_search_send(mem_ctx, ev, cldap, io);
865 if (req == NULL) {
866 TALLOC_FREE(frame);
867 return NT_STATUS_NO_MEMORY;
870 if (!tevent_req_poll(req, ev)) {
871 status = map_nt_error_from_unix_common(errno);
872 TALLOC_FREE(frame);
873 return status;
876 status = cldap_search_recv(req, mem_ctx, io);
877 if (!NT_STATUS_IS_OK(status)) {
878 TALLOC_FREE(frame);
879 return status;
882 TALLOC_FREE(frame);
883 return NT_STATUS_OK;
886 struct cldap_netlogon_state {
887 struct cldap_search search;
890 char *cldap_netlogon_create_filter(TALLOC_CTX *mem_ctx,
891 const struct cldap_netlogon *io)
893 char *filter;
895 filter = talloc_asprintf(mem_ctx, "(&(NtVer=%s)",
896 ldap_encode_ndr_uint32(mem_ctx, io->in.version));
897 if (filter == NULL)
898 return NULL;
900 if (io->in.user) {
901 filter = talloc_asprintf_append_buffer(filter, "(User=%s)", io->in.user);
902 if (filter == NULL) {
903 return NULL;
906 if (io->in.host) {
907 filter = talloc_asprintf_append_buffer(filter, "(Host=%s)", io->in.host);
908 if (filter == NULL) {
909 return NULL;
912 if (io->in.realm) {
913 filter = talloc_asprintf_append_buffer(filter, "(DnsDomain=%s)", io->in.realm);
914 if (filter == NULL) {
915 return NULL;
918 if (io->in.acct_control != -1) {
919 filter = talloc_asprintf_append_buffer(filter, "(AAC=%s)",
920 ldap_encode_ndr_uint32(mem_ctx, io->in.acct_control));
921 if (filter == NULL) {
922 return NULL;
925 if (io->in.domain_sid) {
926 struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, io->in.domain_sid);
928 filter = talloc_asprintf_append_buffer(filter, "(domainSid=%s)",
929 ldap_encode_ndr_dom_sid(mem_ctx, sid));
930 if (filter == NULL) {
931 return NULL;
934 if (io->in.domain_guid) {
935 struct GUID guid;
936 GUID_from_string(io->in.domain_guid, &guid);
938 filter = talloc_asprintf_append_buffer(filter, "(DomainGuid=%s)",
939 ldap_encode_ndr_GUID(mem_ctx, &guid));
940 if (filter == NULL) {
941 return NULL;
944 filter = talloc_asprintf_append_buffer(filter, ")");
946 return filter;
949 static void cldap_netlogon_state_done(struct tevent_req *subreq);
951 queue a cldap netlogon for send
953 struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
954 struct tevent_context *ev,
955 struct cldap_socket *cldap,
956 const struct cldap_netlogon *io)
958 struct tevent_req *req, *subreq;
959 struct cldap_netlogon_state *state;
960 char *filter;
961 static const char * const attr[] = { "NetLogon", NULL };
963 req = tevent_req_create(mem_ctx, &state,
964 struct cldap_netlogon_state);
965 if (!req) {
966 return NULL;
969 filter = cldap_netlogon_create_filter(state, io);
970 if (tevent_req_nomem(filter, req)) {
971 goto post;
974 if (io->in.dest_address) {
975 state->search.in.dest_address = talloc_strdup(state,
976 io->in.dest_address);
977 if (tevent_req_nomem(state->search.in.dest_address, req)) {
978 goto post;
980 state->search.in.dest_port = io->in.dest_port;
981 } else {
982 state->search.in.dest_address = NULL;
983 state->search.in.dest_port = 0;
985 state->search.in.filter = filter;
986 state->search.in.attributes = attr;
987 state->search.in.timeout = 2;
988 state->search.in.retries = 2;
990 subreq = cldap_search_send(state, ev, cldap, &state->search);
991 if (tevent_req_nomem(subreq, req)) {
992 goto post;
994 tevent_req_set_callback(subreq, cldap_netlogon_state_done, req);
996 return req;
997 post:
998 return tevent_req_post(req, ev);
1001 static void cldap_netlogon_state_done(struct tevent_req *subreq)
1003 struct tevent_req *req = tevent_req_callback_data(subreq,
1004 struct tevent_req);
1005 struct cldap_netlogon_state *state = tevent_req_data(req,
1006 struct cldap_netlogon_state);
1007 NTSTATUS status;
1009 status = cldap_search_recv(subreq, state, &state->search);
1010 talloc_free(subreq);
1012 if (tevent_req_nterror(req, status)) {
1013 return;
1016 tevent_req_done(req);
1020 receive a cldap netlogon reply
1022 NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
1023 TALLOC_CTX *mem_ctx,
1024 struct cldap_netlogon *io)
1026 struct cldap_netlogon_state *state = tevent_req_data(req,
1027 struct cldap_netlogon_state);
1028 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1029 DATA_BLOB *data;
1031 if (tevent_req_is_nterror(req, &status)) {
1032 goto failed;
1035 if (state->search.out.response == NULL) {
1036 status = NT_STATUS_NOT_FOUND;
1037 goto failed;
1040 if (state->search.out.response->num_attributes != 1 ||
1041 strcasecmp(state->search.out.response->attributes[0].name, "netlogon") != 0 ||
1042 state->search.out.response->attributes[0].num_values != 1 ||
1043 state->search.out.response->attributes[0].values->length < 2) {
1044 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1045 goto failed;
1047 data = state->search.out.response->attributes[0].values;
1049 status = pull_netlogon_samlogon_response(data, mem_ctx,
1050 &io->out.netlogon);
1051 if (!NT_STATUS_IS_OK(status)) {
1052 goto failed;
1055 if (io->in.map_response) {
1056 map_netlogon_samlogon_response(&io->out.netlogon);
1059 status = NT_STATUS_OK;
1060 failed:
1061 tevent_req_received(req);
1062 return status;
1066 sync cldap netlogon search
1068 NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
1069 TALLOC_CTX *mem_ctx,
1070 struct cldap_netlogon *io)
1072 TALLOC_CTX *frame;
1073 struct tevent_req *req;
1074 struct tevent_context *ev;
1075 NTSTATUS status;
1077 if (cldap->searches.list) {
1078 return NT_STATUS_PIPE_BUSY;
1081 if (cldap->incoming.handler) {
1082 return NT_STATUS_INVALID_PIPE_STATE;
1085 frame = talloc_stackframe();
1087 ev = samba_tevent_context_init(frame);
1088 if (ev == NULL) {
1089 TALLOC_FREE(frame);
1090 return NT_STATUS_NO_MEMORY;
1093 req = cldap_netlogon_send(mem_ctx, ev, cldap, io);
1094 if (req == NULL) {
1095 TALLOC_FREE(frame);
1096 return NT_STATUS_NO_MEMORY;
1099 if (!tevent_req_poll(req, ev)) {
1100 status = map_nt_error_from_unix_common(errno);
1101 TALLOC_FREE(frame);
1102 return status;
1105 status = cldap_netlogon_recv(req, mem_ctx, io);
1106 if (!NT_STATUS_IS_OK(status)) {
1107 TALLOC_FREE(frame);
1108 return status;
1111 TALLOC_FREE(frame);
1112 return NT_STATUS_OK;
1117 send an empty reply (used on any error, so the client doesn't keep waiting
1118 or send the bad request again)
1120 NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
1121 uint32_t message_id,
1122 struct tsocket_address *dest)
1124 NTSTATUS status;
1125 struct cldap_reply reply;
1126 struct ldap_Result result;
1128 reply.messageid = message_id;
1129 reply.dest = dest;
1130 reply.response = NULL;
1131 reply.result = &result;
1133 ZERO_STRUCT(result);
1135 status = cldap_reply_send(cldap, &reply);
1137 return status;
1141 send an error reply (used on any error, so the client doesn't keep waiting
1142 or send the bad request again)
1144 NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
1145 uint32_t message_id,
1146 struct tsocket_address *dest,
1147 int resultcode,
1148 const char *errormessage)
1150 NTSTATUS status;
1151 struct cldap_reply reply;
1152 struct ldap_Result result;
1154 reply.messageid = message_id;
1155 reply.dest = dest;
1156 reply.response = NULL;
1157 reply.result = &result;
1159 ZERO_STRUCT(result);
1160 result.resultcode = resultcode;
1161 result.errormessage = errormessage;
1163 status = cldap_reply_send(cldap, &reply);
1165 return status;
1170 send a netlogon reply
1172 NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
1173 uint32_t message_id,
1174 struct tsocket_address *dest,
1175 uint32_t version,
1176 struct netlogon_samlogon_response *netlogon)
1178 NTSTATUS status;
1179 struct cldap_reply reply;
1180 struct ldap_SearchResEntry response;
1181 struct ldap_Result result;
1182 TALLOC_CTX *tmp_ctx = talloc_new(cldap);
1183 DATA_BLOB blob;
1185 status = push_netlogon_samlogon_response(&blob, tmp_ctx,
1186 netlogon);
1187 if (!NT_STATUS_IS_OK(status)) {
1188 talloc_free(tmp_ctx);
1189 return status;
1191 reply.messageid = message_id;
1192 reply.dest = dest;
1193 reply.response = &response;
1194 reply.result = &result;
1196 ZERO_STRUCT(result);
1198 response.dn = "";
1199 response.num_attributes = 1;
1200 response.attributes = talloc(tmp_ctx, struct ldb_message_element);
1201 NT_STATUS_HAVE_NO_MEMORY(response.attributes);
1202 response.attributes->name = "netlogon";
1203 response.attributes->num_values = 1;
1204 response.attributes->values = &blob;
1206 status = cldap_reply_send(cldap, &reply);
1208 talloc_free(tmp_ctx);
1210 return status;