2 Unix SMB/CIFS implementation.
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
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
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"
46 #include "lib/util/idtree_random.h"
51 context structure for operations on cldap packets
54 /* the low level socket */
55 struct tdgram_context *sock;
58 * Are we in connected mode, which means
59 * we get ICMP errors back instead of timing
60 * out requests. And we can only send requests
61 * to the connected peer.
65 /* the queue for outgoing dgrams */
66 struct tevent_queue *send_queue;
68 /* do we have an async tsocket_recvfrom request pending */
69 struct tevent_req *recv_subreq;
72 /* a queue of pending search requests */
73 struct cldap_search_state *list;
75 /* mapping from message_id to pending request */
76 struct idr_context *idr;
79 /* what to do with incoming request packets */
81 struct tevent_context *ev;
82 void (*handler)(struct cldap_socket *,
84 struct cldap_incoming *);
89 struct cldap_search_state {
90 struct cldap_search_state *prev, *next;
93 struct tevent_context *ev;
94 struct cldap_socket *cldap;
103 struct tsocket_address *dest;
108 struct cldap_incoming *in;
109 struct asn1_data *asn1;
112 struct tevent_req *req;
116 * For CLDAP we limit the maximum search request size to 4kb
118 #define MAX_SEARCH_REQUEST 4096
120 static int cldap_socket_destructor(struct cldap_socket *c)
122 while (c->searches.list) {
123 struct cldap_search_state *s = c->searches.list;
124 DLIST_REMOVE(c->searches.list, s);
125 ZERO_STRUCT(s->caller);
128 talloc_free(c->recv_subreq);
129 talloc_free(c->send_queue);
130 talloc_free(c->sock);
134 static void cldap_recvfrom_done(struct tevent_req *subreq);
136 static bool cldap_recvfrom_setup(struct cldap_socket *c)
138 struct tevent_context *ev;
140 if (c->recv_subreq) {
144 if (!c->searches.list && !c->incoming.handler) {
150 /* this shouldn't happen but should be protected against */
151 if (c->searches.list == NULL) {
154 ev = c->searches.list->caller.ev;
157 c->recv_subreq = tdgram_recvfrom_send(c, ev, c->sock);
158 if (!c->recv_subreq) {
161 tevent_req_set_callback(c->recv_subreq, cldap_recvfrom_done, c);
166 static void cldap_recvfrom_stop(struct cldap_socket *c)
168 if (!c->recv_subreq) {
172 if (c->searches.list || c->incoming.handler) {
176 talloc_free(c->recv_subreq);
177 c->recv_subreq = NULL;
180 static bool cldap_socket_recv_dgram(struct cldap_socket *c,
181 struct cldap_incoming *in);
183 static void cldap_recvfrom_done(struct tevent_req *subreq)
185 struct cldap_socket *c = tevent_req_callback_data(subreq,
186 struct cldap_socket);
187 struct cldap_incoming *in = NULL;
191 c->recv_subreq = NULL;
193 in = talloc_zero(c, struct cldap_incoming);
198 ret = tdgram_recvfrom_recv(subreq,
208 if (ret == -1 && in->recv_errno == 0) {
209 in->recv_errno = EIO;
212 /* this function should free or steal 'in' */
213 setup_done = cldap_socket_recv_dgram(c, in);
216 if (!setup_done && !cldap_recvfrom_setup(c)) {
228 handle recv events on a cldap socket
230 static bool cldap_socket_recv_dgram(struct cldap_socket *c,
231 struct cldap_incoming *in)
233 struct asn1_data *asn1;
235 struct cldap_search_state *search;
237 struct ldap_request_limits limits = {
238 .max_search_size = MAX_SEARCH_REQUEST
241 if (in->recv_errno != 0) {
245 asn1 = asn1_init(in, ASN1_MAX_TREE_DEPTH);
250 asn1_load_nocopy(asn1, in->buf, in->len);
252 in->ldap_msg = talloc(in, struct ldap_message);
253 if (in->ldap_msg == NULL) {
257 /* this initial decode is used to find the message id */
258 status = ldap_decode(asn1, &limits, NULL, in->ldap_msg);
259 if (!NT_STATUS_IS_OK(status)) {
263 /* find the pending request */
264 p = idr_find(c->searches.idr, in->ldap_msg->messageid);
266 if (!c->incoming.handler) {
271 /* this function should free or steal 'in' */
272 c->incoming.handler(c, c->incoming.private_data, in);
276 search = talloc_get_type_abort(p, struct cldap_search_state);
277 search->response.in = talloc_move(search, &in);
279 search->response.asn1 = asn1;
281 asn1_load_nocopy(search->response.asn1,
282 search->response.in->buf, search->response.in->len);
284 DLIST_REMOVE(c->searches.list, search);
286 if (cldap_recvfrom_setup(c)) {
287 tevent_req_done(search->req);
292 * This request was ok, just defer the notify of the caller
293 * and then just fail the next request if needed
295 tevent_req_defer_callback(search->req, search->caller.ev);
296 tevent_req_done(search->req);
298 status = NT_STATUS_NO_MEMORY;
299 /* in is NULL it this point */
302 in->recv_errno = ENOMEM;
304 status = map_nt_error_from_unix_common(in->recv_errno);
307 /* in connected mode the first pending search gets the error */
309 /* otherwise we just ignore the error */
312 if (!c->searches.list) {
316 * We might called tevent_req_done() for a successful
317 * search before, so we better deliver the failure
318 * after the success, that is why we better also
319 * use tevent_req_defer_callback() here.
321 tevent_req_defer_callback(c->searches.list->req,
322 c->searches.list->caller.ev);
323 tevent_req_nterror(c->searches.list->req, status);
328 initialise a cldap_sock
330 NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx,
331 const struct tsocket_address *local_addr,
332 const struct tsocket_address *remote_addr,
333 struct cldap_socket **_cldap)
335 struct cldap_socket *c = NULL;
336 struct tsocket_address *any = NULL;
339 const char *fam = NULL;
341 if (local_addr == NULL && remote_addr == NULL) {
342 return NT_STATUS_INVALID_PARAMETER_MIX;
349 is_ipv4 = tsocket_address_is_inet(remote_addr, "ipv4");
350 is_ipv6 = tsocket_address_is_inet(remote_addr, "ipv6");
354 } else if (is_ipv6) {
357 return NT_STATUS_INVALID_ADDRESS;
361 c = talloc_zero(mem_ctx, struct cldap_socket);
368 * Here we know the address family of the remote address.
371 return NT_STATUS_INVALID_PARAMETER_MIX;
374 ret = tsocket_address_inet_from_strings(c, fam,
378 status = map_nt_error_from_unix_common(errno);
384 c->searches.idr = idr_init(c);
385 if (!c->searches.idr) {
389 ret = tdgram_inet_udp_socket(local_addr, remote_addr,
392 status = map_nt_error_from_unix_common(errno);
401 c->send_queue = tevent_queue_create(c, "cldap_send_queue");
402 if (!c->send_queue) {
406 talloc_set_destructor(c, cldap_socket_destructor);
412 status = NT_STATUS_NO_MEMORY;
419 setup a handler for incoming requests
421 NTSTATUS cldap_set_incoming_handler(struct cldap_socket *c,
422 struct tevent_context *ev,
423 void (*handler)(struct cldap_socket *,
425 struct cldap_incoming *),
429 return NT_STATUS_PIPE_CONNECTED;
433 c->incoming.handler = handler;
434 c->incoming.private_data = private_data;
436 if (!cldap_recvfrom_setup(c)) {
437 ZERO_STRUCT(c->incoming);
438 return NT_STATUS_NO_MEMORY;
444 struct cldap_reply_state {
445 struct tsocket_address *dest;
449 static void cldap_reply_state_destroy(struct tevent_req *subreq);
452 queue a cldap reply for send
454 NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
456 struct cldap_reply_state *state = NULL;
457 struct ldap_message *msg;
458 DATA_BLOB blob1, blob2;
460 struct tevent_req *subreq;
462 if (cldap->connected) {
463 return NT_STATUS_PIPE_CONNECTED;
466 if (cldap->incoming.ev == NULL) {
467 return NT_STATUS_INVALID_PIPE_STATE;
471 return NT_STATUS_INVALID_ADDRESS;
474 state = talloc(cldap, struct cldap_reply_state);
475 NT_STATUS_HAVE_NO_MEMORY(state);
477 state->dest = tsocket_address_copy(io->dest, state);
482 msg = talloc(state, struct ldap_message);
487 msg->messageid = io->messageid;
488 msg->controls = NULL;
491 msg->type = LDAP_TAG_SearchResultEntry;
492 msg->r.SearchResultEntry = *io->response;
494 if (!ldap_encode(msg, NULL, &blob1, state)) {
495 status = NT_STATUS_INVALID_PARAMETER;
499 blob1 = data_blob(NULL, 0);
502 msg->type = LDAP_TAG_SearchResultDone;
503 msg->r.SearchResultDone = *io->result;
505 if (!ldap_encode(msg, NULL, &blob2, state)) {
506 status = NT_STATUS_INVALID_PARAMETER;
511 state->blob = data_blob_talloc(state, NULL, blob1.length + blob2.length);
512 if (!state->blob.data) {
516 if (blob1.data != NULL) {
517 memcpy(state->blob.data, blob1.data, blob1.length);
519 memcpy(state->blob.data+blob1.length, blob2.data, blob2.length);
520 data_blob_free(&blob1);
521 data_blob_free(&blob2);
523 subreq = tdgram_sendto_queue_send(state,
533 /* the callback will just free the state, as we don't need a result */
534 tevent_req_set_callback(subreq, cldap_reply_state_destroy, state);
539 status = NT_STATUS_NO_MEMORY;
545 static void cldap_reply_state_destroy(struct tevent_req *subreq)
547 struct cldap_reply_state *state = tevent_req_callback_data(subreq,
548 struct cldap_reply_state);
550 /* we don't want to know the result here, we just free the state */
555 static int cldap_search_state_destructor(struct cldap_search_state *s)
557 if (s->caller.cldap) {
558 if (s->message_id != -1) {
559 idr_remove(s->caller.cldap->searches.idr, s->message_id);
562 DLIST_REMOVE(s->caller.cldap->searches.list, s);
563 cldap_recvfrom_stop(s->caller.cldap);
564 ZERO_STRUCT(s->caller);
570 static void cldap_search_state_queue_done(struct tevent_req *subreq);
571 static void cldap_search_state_wakeup_done(struct tevent_req *subreq);
574 queue a cldap reply for send
576 struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
577 struct tevent_context *ev,
578 struct cldap_socket *cldap,
579 const struct cldap_search *io)
581 struct tevent_req *req, *subreq;
582 struct cldap_search_state *state = NULL;
583 struct ldap_message *msg;
584 struct ldap_SearchRequest *search;
590 req = tevent_req_create(mem_ctx, &state,
591 struct cldap_search_state);
595 state->caller.ev = ev;
597 state->caller.cldap = cldap;
598 state->message_id = -1;
600 talloc_set_destructor(state, cldap_search_state_destructor);
602 if (state->caller.cldap == NULL) {
603 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
607 if (io->in.dest_address) {
608 if (cldap->connected) {
609 tevent_req_nterror(req, NT_STATUS_PIPE_CONNECTED);
612 ret = tsocket_address_inet_from_strings(state,
616 &state->request.dest);
618 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
622 if (!cldap->connected) {
623 tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
626 state->request.dest = NULL;
629 state->message_id = idr_get_new_random(
630 cldap->searches.idr, state, 1, UINT16_MAX);
631 if (state->message_id == -1) {
632 tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
636 msg = talloc(state, struct ldap_message);
637 if (tevent_req_nomem(msg, req)) {
641 msg->messageid = state->message_id;
642 msg->type = LDAP_TAG_SearchRequest;
643 msg->controls = NULL;
644 search = &msg->r.SearchRequest;
647 search->scope = LDAP_SEARCH_SCOPE_BASE;
648 search->deref = LDAP_DEREFERENCE_NEVER;
649 search->timelimit = 0;
650 search->sizelimit = 0;
651 search->attributesonly = false;
652 search->num_attributes = str_list_length(io->in.attributes);
653 search->attributes = io->in.attributes;
654 search->tree = ldb_parse_tree(msg, io->in.filter);
655 if (tevent_req_nomem(search->tree, req)) {
659 if (!ldap_encode(msg, NULL, &state->request.blob, state)) {
660 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
665 state->request.idx = 0;
666 state->request.delay = 10*1000*1000;
667 state->request.count = 3;
668 if (io->in.timeout > 0) {
669 state->request.delay = io->in.timeout * 1000 * 1000;
670 state->request.count = io->in.retries + 1;
673 now = tevent_timeval_current();
675 for (i = 0; i < state->request.count; i++) {
676 end = tevent_timeval_add(&end, state->request.delay / 1000000,
677 state->request.delay % 1000000);
680 if (!tevent_req_set_endtime(req, state->caller.ev, end)) {
684 subreq = tdgram_sendto_queue_send(state,
686 state->caller.cldap->sock,
687 state->caller.cldap->send_queue,
688 state->request.blob.data,
689 state->request.blob.length,
690 state->request.dest);
691 if (tevent_req_nomem(subreq, req)) {
694 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
696 DLIST_ADD_END(cldap->searches.list, state);
701 return tevent_req_post(req, state->caller.ev);
704 static void cldap_search_state_queue_done(struct tevent_req *subreq)
706 struct tevent_req *req = tevent_req_callback_data(subreq,
708 struct cldap_search_state *state = tevent_req_data(req,
709 struct cldap_search_state);
714 ret = tdgram_sendto_queue_recv(subreq, &sys_errno);
718 status = map_nt_error_from_unix_common(sys_errno);
719 DLIST_REMOVE(state->caller.cldap->searches.list, state);
720 ZERO_STRUCT(state->caller.cldap);
721 tevent_req_nterror(req, status);
725 state->request.idx++;
727 /* wait for incoming traffic */
728 if (!cldap_recvfrom_setup(state->caller.cldap)) {
733 if (state->request.idx > state->request.count) {
734 /* we just wait for the response or a timeout */
738 next = tevent_timeval_current_ofs(state->request.delay / 1000000,
739 state->request.delay % 1000000);
740 subreq = tevent_wakeup_send(state,
743 if (tevent_req_nomem(subreq, req)) {
746 tevent_req_set_callback(subreq, cldap_search_state_wakeup_done, req);
749 static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
751 struct tevent_req *req = tevent_req_callback_data(subreq,
753 struct cldap_search_state *state = tevent_req_data(req,
754 struct cldap_search_state);
757 ok = tevent_wakeup_recv(subreq);
760 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
764 subreq = tdgram_sendto_queue_send(state,
766 state->caller.cldap->sock,
767 state->caller.cldap->send_queue,
768 state->request.blob.data,
769 state->request.blob.length,
770 state->request.dest);
771 if (tevent_req_nomem(subreq, req)) {
774 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
778 receive a cldap reply
780 NTSTATUS cldap_search_recv(struct tevent_req *req,
782 struct cldap_search *io)
784 struct cldap_search_state *state = tevent_req_data(req,
785 struct cldap_search_state);
786 struct ldap_message *ldap_msg;
788 struct ldap_request_limits limits = {
789 .max_search_size = MAX_SEARCH_REQUEST
792 if (tevent_req_is_nterror(req, &status)) {
796 ldap_msg = talloc(mem_ctx, struct ldap_message);
801 status = ldap_decode(state->response.asn1, &limits, NULL, ldap_msg);
802 if (!NT_STATUS_IS_OK(status)) {
806 ZERO_STRUCT(io->out);
808 /* the first possible form has a search result in first place */
809 if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
810 io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
811 if (!io->out.response) {
814 *io->out.response = ldap_msg->r.SearchResultEntry;
816 /* decode the 2nd part */
817 status = ldap_decode(
818 state->response.asn1, &limits, NULL, ldap_msg);
819 if (!NT_STATUS_IS_OK(status)) {
824 if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
825 status = NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
829 io->out.result = talloc(mem_ctx, struct ldap_Result);
830 if (!io->out.result) {
833 *io->out.result = ldap_msg->r.SearchResultDone;
835 if (io->out.result->resultcode != LDAP_SUCCESS) {
836 status = NT_STATUS_LDAP(io->out.result->resultcode);
840 tevent_req_received(req);
844 status = NT_STATUS_NO_MEMORY;
846 tevent_req_received(req);
852 synchronous cldap search
854 NTSTATUS cldap_search(struct cldap_socket *cldap,
856 struct cldap_search *io)
859 struct tevent_req *req;
860 struct tevent_context *ev;
863 if (cldap->searches.list) {
864 return NT_STATUS_PIPE_BUSY;
867 if (cldap->incoming.handler) {
868 return NT_STATUS_INVALID_PIPE_STATE;
871 frame = talloc_stackframe();
873 ev = samba_tevent_context_init(frame);
876 return NT_STATUS_NO_MEMORY;
879 req = cldap_search_send(mem_ctx, ev, cldap, io);
882 return NT_STATUS_NO_MEMORY;
885 if (!tevent_req_poll(req, ev)) {
886 status = map_nt_error_from_unix_common(errno);
891 status = cldap_search_recv(req, mem_ctx, io);
892 if (!NT_STATUS_IS_OK(status)) {
901 struct cldap_netlogon_state {
902 struct cldap_search search;
905 char *cldap_netlogon_create_filter(TALLOC_CTX *mem_ctx,
906 const struct cldap_netlogon *io)
910 filter = talloc_asprintf(mem_ctx, "(&(NtVer=%s)",
911 ldap_encode_ndr_uint32(mem_ctx, io->in.version));
914 talloc_asprintf_addbuf(&filter, "(User=%s)", io->in.user);
917 talloc_asprintf_addbuf(&filter, "(Host=%s)", io->in.host);
920 talloc_asprintf_addbuf(&filter, "(DnsDomain=%s)", io->in.realm);
922 if (io->in.acct_control != -1) {
923 talloc_asprintf_addbuf(
926 ldap_encode_ndr_uint32(mem_ctx, io->in.acct_control));
928 if (io->in.domain_sid) {
929 struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, io->in.domain_sid);
931 talloc_asprintf_addbuf(&filter, "(domainSid=%s)",
932 ldap_encode_ndr_dom_sid(mem_ctx, sid));
934 if (io->in.domain_guid) {
936 GUID_from_string(io->in.domain_guid, &guid);
938 talloc_asprintf_addbuf(&filter, "(DomainGuid=%s)",
939 ldap_encode_ndr_GUID(mem_ctx, &guid));
941 talloc_asprintf_addbuf(&filter, ")");
946 static void cldap_netlogon_state_done(struct tevent_req *subreq);
948 queue a cldap netlogon for send
950 struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
951 struct tevent_context *ev,
952 struct cldap_socket *cldap,
953 const struct cldap_netlogon *io)
955 struct tevent_req *req, *subreq;
956 struct cldap_netlogon_state *state;
958 static const char * const attr[] = { "NetLogon", NULL };
960 req = tevent_req_create(mem_ctx, &state,
961 struct cldap_netlogon_state);
966 filter = cldap_netlogon_create_filter(state, io);
967 if (tevent_req_nomem(filter, req)) {
971 if (io->in.dest_address) {
972 state->search.in.dest_address = talloc_strdup(state,
973 io->in.dest_address);
974 if (tevent_req_nomem(state->search.in.dest_address, req)) {
977 state->search.in.dest_port = io->in.dest_port;
979 state->search.in.dest_address = NULL;
980 state->search.in.dest_port = 0;
982 state->search.in.filter = filter;
983 state->search.in.attributes = attr;
984 state->search.in.timeout = 2;
985 state->search.in.retries = 2;
987 subreq = cldap_search_send(state, ev, cldap, &state->search);
988 if (tevent_req_nomem(subreq, req)) {
991 tevent_req_set_callback(subreq, cldap_netlogon_state_done, req);
995 return tevent_req_post(req, ev);
998 static void cldap_netlogon_state_done(struct tevent_req *subreq)
1000 struct tevent_req *req = tevent_req_callback_data(subreq,
1002 struct cldap_netlogon_state *state = tevent_req_data(req,
1003 struct cldap_netlogon_state);
1006 status = cldap_search_recv(subreq, state, &state->search);
1007 talloc_free(subreq);
1009 if (tevent_req_nterror(req, status)) {
1013 tevent_req_done(req);
1017 receive a cldap netlogon reply
1019 NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
1020 TALLOC_CTX *mem_ctx,
1021 struct cldap_netlogon *io)
1023 struct cldap_netlogon_state *state = tevent_req_data(req,
1024 struct cldap_netlogon_state);
1025 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1028 if (tevent_req_is_nterror(req, &status)) {
1032 if (state->search.out.response == NULL) {
1033 status = NT_STATUS_NOT_FOUND;
1037 if (state->search.out.response->num_attributes != 1 ||
1038 strcasecmp(state->search.out.response->attributes[0].name, "netlogon") != 0 ||
1039 state->search.out.response->attributes[0].num_values != 1 ||
1040 state->search.out.response->attributes[0].values->length < 2) {
1041 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1044 data = state->search.out.response->attributes[0].values;
1046 status = pull_netlogon_samlogon_response(data, mem_ctx,
1048 if (!NT_STATUS_IS_OK(status)) {
1052 if (io->in.map_response) {
1053 map_netlogon_samlogon_response(&io->out.netlogon);
1056 status = NT_STATUS_OK;
1058 tevent_req_received(req);
1063 sync cldap netlogon search
1065 NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
1066 TALLOC_CTX *mem_ctx,
1067 struct cldap_netlogon *io)
1070 struct tevent_req *req;
1071 struct tevent_context *ev;
1074 if (cldap->searches.list) {
1075 return NT_STATUS_PIPE_BUSY;
1078 if (cldap->incoming.handler) {
1079 return NT_STATUS_INVALID_PIPE_STATE;
1082 frame = talloc_stackframe();
1084 ev = samba_tevent_context_init(frame);
1087 return NT_STATUS_NO_MEMORY;
1090 req = cldap_netlogon_send(mem_ctx, ev, cldap, io);
1093 return NT_STATUS_NO_MEMORY;
1096 if (!tevent_req_poll(req, ev)) {
1097 status = map_nt_error_from_unix_common(errno);
1102 status = cldap_netlogon_recv(req, mem_ctx, io);
1103 if (!NT_STATUS_IS_OK(status)) {
1109 return NT_STATUS_OK;
1114 send an empty reply (used on any error, so the client doesn't keep waiting
1115 or send the bad request again)
1117 NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
1118 uint32_t message_id,
1119 struct tsocket_address *dest)
1122 struct cldap_reply reply;
1123 struct ldap_Result result;
1125 reply.messageid = message_id;
1127 reply.response = NULL;
1128 reply.result = &result;
1130 ZERO_STRUCT(result);
1132 status = cldap_reply_send(cldap, &reply);
1138 send an error reply (used on any error, so the client doesn't keep waiting
1139 or send the bad request again)
1141 NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
1142 uint32_t message_id,
1143 struct tsocket_address *dest,
1145 const char *errormessage)
1148 struct cldap_reply reply;
1149 struct ldap_Result result;
1151 reply.messageid = message_id;
1153 reply.response = NULL;
1154 reply.result = &result;
1156 ZERO_STRUCT(result);
1157 result.resultcode = resultcode;
1158 result.errormessage = errormessage;
1160 status = cldap_reply_send(cldap, &reply);
1167 send a netlogon reply
1169 NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
1170 uint32_t message_id,
1171 struct tsocket_address *dest,
1173 struct netlogon_samlogon_response *netlogon)
1176 struct cldap_reply reply;
1177 struct ldap_SearchResEntry response;
1178 struct ldap_Result result;
1179 TALLOC_CTX *tmp_ctx = talloc_new(cldap);
1182 status = push_netlogon_samlogon_response(&blob, tmp_ctx,
1184 if (!NT_STATUS_IS_OK(status)) {
1185 talloc_free(tmp_ctx);
1188 reply.messageid = message_id;
1190 reply.response = &response;
1191 reply.result = &result;
1193 ZERO_STRUCT(result);
1196 response.num_attributes = 1;
1197 response.attributes = talloc(tmp_ctx, struct ldb_message_element);
1198 NT_STATUS_HAVE_NO_MEMORY(response.attributes);
1199 response.attributes->name = "netlogon";
1200 response.attributes->num_values = 1;
1201 response.attributes->values = &blob;
1203 status = cldap_reply_send(cldap, &reply);
1205 talloc_free(tmp_ctx);