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"
50 context structure for operations on cldap packets
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.
65 * we allow sync requests only, if the caller
66 * did not pass an event context to cldap_socket_init()
70 struct tevent_context *ctx;
73 /* the queue for outgoing dgrams */
74 struct tevent_queue *send_queue;
76 /* do we have an async tsocket_recvfrom request pending */
77 struct tevent_req *recv_subreq;
80 /* a queue of pending search requests */
81 struct cldap_search_state *list;
83 /* mapping from message_id to pending request */
84 struct idr_context *idr;
87 /* what to do with incoming request packets */
89 struct tevent_context *ev;
90 void (*handler)(struct cldap_socket *,
92 struct cldap_incoming *);
97 struct cldap_search_state {
98 struct cldap_search_state *prev, *next;
101 struct cldap_socket *cldap;
110 struct tsocket_address *dest;
115 struct cldap_incoming *in;
116 struct asn1_data *asn1;
119 struct tevent_req *req;
122 static int cldap_socket_destructor(struct cldap_socket *c)
124 while (c->searches.list) {
125 struct cldap_search_state *s = c->searches.list;
126 DLIST_REMOVE(c->searches.list, s);
127 ZERO_STRUCT(s->caller);
130 talloc_free(c->recv_subreq);
131 talloc_free(c->send_queue);
132 talloc_free(c->sock);
136 static void cldap_recvfrom_done(struct tevent_req *subreq);
138 static bool cldap_recvfrom_setup(struct cldap_socket *c)
140 if (c->recv_subreq) {
144 if (!c->searches.list && !c->incoming.handler) {
148 c->recv_subreq = tdgram_recvfrom_send(c, c->event.ctx, c->sock);
149 if (!c->recv_subreq) {
152 tevent_req_set_callback(c->recv_subreq, cldap_recvfrom_done, c);
157 static void cldap_recvfrom_stop(struct cldap_socket *c)
159 if (!c->recv_subreq) {
163 if (c->searches.list || c->incoming.handler) {
167 talloc_free(c->recv_subreq);
168 c->recv_subreq = NULL;
171 static bool cldap_socket_recv_dgram(struct cldap_socket *c,
172 struct cldap_incoming *in);
174 static void cldap_recvfrom_done(struct tevent_req *subreq)
176 struct cldap_socket *c = tevent_req_callback_data(subreq,
177 struct cldap_socket);
178 struct cldap_incoming *in = NULL;
182 c->recv_subreq = NULL;
184 in = talloc_zero(c, struct cldap_incoming);
189 ret = tdgram_recvfrom_recv(subreq,
199 if (ret == -1 && in->recv_errno == 0) {
200 in->recv_errno = EIO;
203 /* this function should free or steal 'in' */
204 setup_done = cldap_socket_recv_dgram(c, in);
207 if (!setup_done && !cldap_recvfrom_setup(c)) {
216 /*TODO: call a dead socket handler */
221 handle recv events on a cldap socket
223 static bool cldap_socket_recv_dgram(struct cldap_socket *c,
224 struct cldap_incoming *in)
227 struct asn1_data *asn1;
229 struct cldap_search_state *search;
232 if (in->recv_errno != 0) {
236 blob = data_blob_const(in->buf, in->len);
238 asn1 = asn1_init(in);
243 if (!asn1_load(asn1, blob)) {
247 in->ldap_msg = talloc(in, struct ldap_message);
248 if (in->ldap_msg == NULL) {
252 /* this initial decode is used to find the message id */
253 status = ldap_decode(asn1, NULL, in->ldap_msg);
254 if (!NT_STATUS_IS_OK(status)) {
258 /* find the pending request */
259 p = idr_find(c->searches.idr, in->ldap_msg->messageid);
261 if (!c->incoming.handler) {
265 /* this function should free or steal 'in' */
266 c->incoming.handler(c, c->incoming.private_data, in);
270 search = talloc_get_type(p, struct cldap_search_state);
271 search->response.in = talloc_move(search, &in);
272 search->response.asn1 = asn1;
273 search->response.asn1->ofs = 0;
275 DLIST_REMOVE(c->searches.list, search);
277 if (!cldap_recvfrom_setup(c)) {
281 tevent_req_done(search->req);
286 in->recv_errno = ENOMEM;
288 status = map_nt_error_from_unix_common(in->recv_errno);
290 /* in connected mode the first pending search gets the error */
292 /* otherwise we just ignore the error */
295 if (!c->searches.list) {
298 tevent_req_nterror(c->searches.list->req, status);
305 initialise a cldap_sock
307 NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx,
308 struct tevent_context *ev,
309 const struct tsocket_address *local_addr,
310 const struct tsocket_address *remote_addr,
311 struct cldap_socket **_cldap)
313 struct cldap_socket *c = NULL;
314 struct tsocket_address *any = NULL;
318 c = talloc_zero(mem_ctx, struct cldap_socket);
324 ev = tevent_context_init(c);
328 c->event.allow_poll = true;
333 /* we use ipv4 here instead of ip, as otherwise we end
334 up with a PF_INET6 socket, and sendto() for ipv4
335 addresses will fail. That breaks cldap name
336 resolution for winbind to IPv4 hosts. */
337 ret = tsocket_address_inet_from_strings(c, "ipv4",
341 status = map_nt_error_from_unix_common(errno);
347 c->searches.idr = idr_init(c);
348 if (!c->searches.idr) {
352 ret = tdgram_inet_udp_socket(local_addr, remote_addr,
355 status = map_nt_error_from_unix_common(errno);
364 c->send_queue = tevent_queue_create(c, "cldap_send_queue");
365 if (!c->send_queue) {
369 talloc_set_destructor(c, cldap_socket_destructor);
375 status = NT_STATUS_NO_MEMORY;
382 setup a handler for incoming requests
384 NTSTATUS cldap_set_incoming_handler(struct cldap_socket *c,
385 struct tevent_context *ev,
386 void (*handler)(struct cldap_socket *,
388 struct cldap_incoming *),
392 return NT_STATUS_PIPE_CONNECTED;
395 /* if sync requests are allowed, we don't allow an incoming handler */
396 if (c->event.allow_poll) {
397 return NT_STATUS_INVALID_PIPE_STATE;
400 c->incoming.handler = handler;
401 c->incoming.private_data = private_data;
403 if (!cldap_recvfrom_setup(c)) {
404 ZERO_STRUCT(c->incoming);
405 return NT_STATUS_NO_MEMORY;
411 struct cldap_reply_state {
412 struct tsocket_address *dest;
416 static void cldap_reply_state_destroy(struct tevent_req *subreq);
419 queue a cldap reply for send
421 NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
423 struct cldap_reply_state *state = NULL;
424 struct ldap_message *msg;
425 DATA_BLOB blob1, blob2;
427 struct tevent_req *subreq;
429 if (cldap->connected) {
430 return NT_STATUS_PIPE_CONNECTED;
434 return NT_STATUS_INVALID_ADDRESS;
437 state = talloc(cldap, struct cldap_reply_state);
438 NT_STATUS_HAVE_NO_MEMORY(state);
440 state->dest = tsocket_address_copy(io->dest, state);
445 msg = talloc(state, struct ldap_message);
450 msg->messageid = io->messageid;
451 msg->controls = NULL;
454 msg->type = LDAP_TAG_SearchResultEntry;
455 msg->r.SearchResultEntry = *io->response;
457 if (!ldap_encode(msg, NULL, &blob1, state)) {
458 status = NT_STATUS_INVALID_PARAMETER;
462 blob1 = data_blob(NULL, 0);
465 msg->type = LDAP_TAG_SearchResultDone;
466 msg->r.SearchResultDone = *io->result;
468 if (!ldap_encode(msg, NULL, &blob2, state)) {
469 status = NT_STATUS_INVALID_PARAMETER;
474 state->blob = data_blob_talloc(state, NULL, blob1.length + blob2.length);
475 if (!state->blob.data) {
479 memcpy(state->blob.data, blob1.data, blob1.length);
480 memcpy(state->blob.data+blob1.length, blob2.data, blob2.length);
481 data_blob_free(&blob1);
482 data_blob_free(&blob2);
484 subreq = tdgram_sendto_queue_send(state,
494 /* the callback will just free the state, as we don't need a result */
495 tevent_req_set_callback(subreq, cldap_reply_state_destroy, state);
500 status = NT_STATUS_NO_MEMORY;
506 static void cldap_reply_state_destroy(struct tevent_req *subreq)
508 struct cldap_reply_state *state = tevent_req_callback_data(subreq,
509 struct cldap_reply_state);
511 /* we don't want to know the result here, we just free the state */
516 static int cldap_search_state_destructor(struct cldap_search_state *s)
518 if (s->caller.cldap) {
519 if (s->message_id != -1) {
520 idr_remove(s->caller.cldap->searches.idr, s->message_id);
523 DLIST_REMOVE(s->caller.cldap->searches.list, s);
524 cldap_recvfrom_stop(s->caller.cldap);
525 ZERO_STRUCT(s->caller);
531 static void cldap_search_state_queue_done(struct tevent_req *subreq);
532 static void cldap_search_state_wakeup_done(struct tevent_req *subreq);
535 queue a cldap reply for send
537 struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
538 struct cldap_socket *cldap,
539 const struct cldap_search *io)
541 struct tevent_req *req, *subreq;
542 struct cldap_search_state *state = NULL;
543 struct ldap_message *msg;
544 struct ldap_SearchRequest *search;
550 req = tevent_req_create(mem_ctx, &state,
551 struct cldap_search_state);
557 state->caller.cldap = cldap;
558 state->message_id = -1;
560 talloc_set_destructor(state, cldap_search_state_destructor);
562 if (io->in.dest_address) {
563 if (cldap->connected) {
564 tevent_req_nterror(req, NT_STATUS_PIPE_CONNECTED);
567 ret = tsocket_address_inet_from_strings(state,
571 &state->request.dest);
573 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
577 if (!cldap->connected) {
578 tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
581 state->request.dest = NULL;
584 state->message_id = idr_get_new_random(cldap->searches.idr,
586 if (state->message_id == -1) {
587 tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
591 msg = talloc(state, struct ldap_message);
592 if (tevent_req_nomem(msg, req)) {
596 msg->messageid = state->message_id;
597 msg->type = LDAP_TAG_SearchRequest;
598 msg->controls = NULL;
599 search = &msg->r.SearchRequest;
602 search->scope = LDAP_SEARCH_SCOPE_BASE;
603 search->deref = LDAP_DEREFERENCE_NEVER;
604 search->timelimit = 0;
605 search->sizelimit = 0;
606 search->attributesonly = false;
607 search->num_attributes = str_list_length(io->in.attributes);
608 search->attributes = io->in.attributes;
609 search->tree = ldb_parse_tree(msg, io->in.filter);
610 if (tevent_req_nomem(search->tree, req)) {
614 if (!ldap_encode(msg, NULL, &state->request.blob, state)) {
615 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
620 state->request.idx = 0;
621 state->request.delay = 10*1000*1000;
622 state->request.count = 3;
623 if (io->in.timeout > 0) {
624 state->request.delay = io->in.timeout * 1000 * 1000;
625 state->request.count = io->in.retries + 1;
628 now = tevent_timeval_current();
630 for (i = 0; i < state->request.count; i++) {
631 end = tevent_timeval_add(&end, state->request.delay / 1000000,
632 state->request.delay % 1000000);
635 if (!tevent_req_set_endtime(req, state->caller.cldap->event.ctx, end)) {
640 subreq = tdgram_sendto_queue_send(state,
641 state->caller.cldap->event.ctx,
642 state->caller.cldap->sock,
643 state->caller.cldap->send_queue,
644 state->request.blob.data,
645 state->request.blob.length,
646 state->request.dest);
647 if (tevent_req_nomem(subreq, req)) {
650 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
652 DLIST_ADD_END(cldap->searches.list, state, struct cldap_search_state *);
657 return tevent_req_post(req, cldap->event.ctx);
660 static void cldap_search_state_queue_done(struct tevent_req *subreq)
662 struct tevent_req *req = tevent_req_callback_data(subreq,
664 struct cldap_search_state *state = tevent_req_data(req,
665 struct cldap_search_state);
670 ret = tdgram_sendto_queue_recv(subreq, &sys_errno);
674 status = map_nt_error_from_unix_common(sys_errno);
675 DLIST_REMOVE(state->caller.cldap->searches.list, state);
676 ZERO_STRUCT(state->caller.cldap);
677 tevent_req_nterror(req, status);
681 state->request.idx++;
683 /* wait for incoming traffic */
684 if (!cldap_recvfrom_setup(state->caller.cldap)) {
689 if (state->request.idx > state->request.count) {
690 /* we just wait for the response or a timeout */
694 next = tevent_timeval_current_ofs(state->request.delay / 1000000,
695 state->request.delay % 1000000);
696 subreq = tevent_wakeup_send(state,
697 state->caller.cldap->event.ctx,
699 if (tevent_req_nomem(subreq, req)) {
702 tevent_req_set_callback(subreq, cldap_search_state_wakeup_done, req);
705 static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
707 struct tevent_req *req = tevent_req_callback_data(subreq,
709 struct cldap_search_state *state = tevent_req_data(req,
710 struct cldap_search_state);
713 ok = tevent_wakeup_recv(subreq);
716 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
720 subreq = tdgram_sendto_queue_send(state,
721 state->caller.cldap->event.ctx,
722 state->caller.cldap->sock,
723 state->caller.cldap->send_queue,
724 state->request.blob.data,
725 state->request.blob.length,
726 state->request.dest);
727 if (tevent_req_nomem(subreq, req)) {
730 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
734 receive a cldap reply
736 NTSTATUS cldap_search_recv(struct tevent_req *req,
738 struct cldap_search *io)
740 struct cldap_search_state *state = tevent_req_data(req,
741 struct cldap_search_state);
742 struct ldap_message *ldap_msg;
745 if (tevent_req_is_nterror(req, &status)) {
749 ldap_msg = talloc(mem_ctx, struct ldap_message);
754 status = ldap_decode(state->response.asn1, NULL, ldap_msg);
755 if (!NT_STATUS_IS_OK(status)) {
759 ZERO_STRUCT(io->out);
761 /* the first possible form has a search result in first place */
762 if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
763 io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
764 if (!io->out.response) {
767 *io->out.response = ldap_msg->r.SearchResultEntry;
769 /* decode the 2nd part */
770 status = ldap_decode(state->response.asn1, NULL, ldap_msg);
771 if (!NT_STATUS_IS_OK(status)) {
776 if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
777 status = NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
781 io->out.result = talloc(mem_ctx, struct ldap_Result);
782 if (!io->out.result) {
785 *io->out.result = ldap_msg->r.SearchResultDone;
787 if (io->out.result->resultcode != LDAP_SUCCESS) {
788 status = NT_STATUS_LDAP(io->out.result->resultcode);
792 tevent_req_received(req);
796 status = NT_STATUS_NO_MEMORY;
798 tevent_req_received(req);
804 synchronous cldap search
806 NTSTATUS cldap_search(struct cldap_socket *cldap,
808 struct cldap_search *io)
810 struct tevent_req *req;
813 if (!cldap->event.allow_poll) {
814 return NT_STATUS_INVALID_PIPE_STATE;
817 if (cldap->searches.list) {
818 return NT_STATUS_PIPE_BUSY;
821 req = cldap_search_send(mem_ctx, cldap, io);
822 NT_STATUS_HAVE_NO_MEMORY(req);
824 if (!tevent_req_poll(req, cldap->event.ctx)) {
826 return NT_STATUS_INTERNAL_ERROR;
829 status = cldap_search_recv(req, mem_ctx, io);
835 struct cldap_netlogon_state {
836 struct cldap_search search;
839 static void cldap_netlogon_state_done(struct tevent_req *subreq);
841 queue a cldap netlogon for send
843 struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
844 struct tevent_context *ev,
845 struct cldap_socket *cldap,
846 const struct cldap_netlogon *io)
848 struct tevent_req *req, *subreq;
849 struct cldap_netlogon_state *state;
851 static const char * const attr[] = { "NetLogon", NULL };
853 req = tevent_req_create(mem_ctx, &state,
854 struct cldap_netlogon_state);
859 filter = talloc_asprintf(state, "(&(NtVer=%s)",
860 ldap_encode_ndr_uint32(state, io->in.version));
861 if (tevent_req_nomem(filter, req)) {
865 filter = talloc_asprintf_append_buffer(filter, "(User=%s)", io->in.user);
866 if (tevent_req_nomem(filter, req)) {
871 filter = talloc_asprintf_append_buffer(filter, "(Host=%s)", io->in.host);
872 if (tevent_req_nomem(filter, req)) {
877 filter = talloc_asprintf_append_buffer(filter, "(DnsDomain=%s)", io->in.realm);
878 if (tevent_req_nomem(filter, req)) {
882 if (io->in.acct_control != -1) {
883 filter = talloc_asprintf_append_buffer(filter, "(AAC=%s)",
884 ldap_encode_ndr_uint32(state, io->in.acct_control));
885 if (tevent_req_nomem(filter, req)) {
889 if (io->in.domain_sid) {
890 struct dom_sid *sid = dom_sid_parse_talloc(state, io->in.domain_sid);
891 if (tevent_req_nomem(sid, req)) {
894 filter = talloc_asprintf_append_buffer(filter, "(domainSid=%s)",
895 ldap_encode_ndr_dom_sid(state, sid));
896 if (tevent_req_nomem(filter, req)) {
900 if (io->in.domain_guid) {
903 status = GUID_from_string(io->in.domain_guid, &guid);
904 if (tevent_req_nterror(req, status)) {
907 filter = talloc_asprintf_append_buffer(filter, "(DomainGuid=%s)",
908 ldap_encode_ndr_GUID(state, &guid));
909 if (tevent_req_nomem(filter, req)) {
913 filter = talloc_asprintf_append_buffer(filter, ")");
914 if (tevent_req_nomem(filter, req)) {
918 if (io->in.dest_address) {
919 state->search.in.dest_address = talloc_strdup(state,
920 io->in.dest_address);
921 if (tevent_req_nomem(state->search.in.dest_address, req)) {
924 state->search.in.dest_port = io->in.dest_port;
926 state->search.in.dest_address = NULL;
927 state->search.in.dest_port = 0;
929 state->search.in.filter = filter;
930 state->search.in.attributes = attr;
931 state->search.in.timeout = 2;
932 state->search.in.retries = 2;
934 subreq = cldap_search_send(state, cldap, &state->search);
935 if (tevent_req_nomem(subreq, req)) {
938 tevent_req_set_callback(subreq, cldap_netlogon_state_done, req);
942 return tevent_req_post(req, cldap->event.ctx);
945 static void cldap_netlogon_state_done(struct tevent_req *subreq)
947 struct tevent_req *req = tevent_req_callback_data(subreq,
949 struct cldap_netlogon_state *state = tevent_req_data(req,
950 struct cldap_netlogon_state);
953 status = cldap_search_recv(subreq, state, &state->search);
956 if (tevent_req_nterror(req, status)) {
960 tevent_req_done(req);
964 receive a cldap netlogon reply
966 NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
968 struct cldap_netlogon *io)
970 struct cldap_netlogon_state *state = tevent_req_data(req,
971 struct cldap_netlogon_state);
975 if (tevent_req_is_nterror(req, &status)) {
979 if (state->search.out.response == NULL) {
980 status = NT_STATUS_NOT_FOUND;
984 if (state->search.out.response->num_attributes != 1 ||
985 strcasecmp(state->search.out.response->attributes[0].name, "netlogon") != 0 ||
986 state->search.out.response->attributes[0].num_values != 1 ||
987 state->search.out.response->attributes[0].values->length < 2) {
988 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
991 data = state->search.out.response->attributes[0].values;
993 status = pull_netlogon_samlogon_response(data, mem_ctx,
995 if (!NT_STATUS_IS_OK(status)) {
999 if (io->in.map_response) {
1000 map_netlogon_samlogon_response(&io->out.netlogon);
1003 status = NT_STATUS_OK;
1005 tevent_req_received(req);
1010 sync cldap netlogon search
1012 NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
1013 TALLOC_CTX *mem_ctx,
1014 struct cldap_netlogon *io)
1016 struct tevent_req *req;
1019 if (!cldap->event.allow_poll) {
1020 return NT_STATUS_INVALID_PIPE_STATE;
1023 if (cldap->searches.list) {
1024 return NT_STATUS_PIPE_BUSY;
1027 req = cldap_netlogon_send(mem_ctx, cldap->event.ctx, cldap, io);
1028 NT_STATUS_HAVE_NO_MEMORY(req);
1030 if (!tevent_req_poll(req, cldap->event.ctx)) {
1032 return NT_STATUS_INTERNAL_ERROR;
1035 status = cldap_netlogon_recv(req, mem_ctx, io);
1043 send an empty reply (used on any error, so the client doesn't keep waiting
1044 or send the bad request again)
1046 NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
1047 uint32_t message_id,
1048 struct tsocket_address *dest)
1051 struct cldap_reply reply;
1052 struct ldap_Result result;
1054 reply.messageid = message_id;
1056 reply.response = NULL;
1057 reply.result = &result;
1059 ZERO_STRUCT(result);
1061 status = cldap_reply_send(cldap, &reply);
1067 send an error reply (used on any error, so the client doesn't keep waiting
1068 or send the bad request again)
1070 NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
1071 uint32_t message_id,
1072 struct tsocket_address *dest,
1074 const char *errormessage)
1077 struct cldap_reply reply;
1078 struct ldap_Result result;
1080 reply.messageid = message_id;
1082 reply.response = NULL;
1083 reply.result = &result;
1085 ZERO_STRUCT(result);
1086 result.resultcode = resultcode;
1087 result.errormessage = errormessage;
1089 status = cldap_reply_send(cldap, &reply);
1096 send a netlogon reply
1098 NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
1099 uint32_t message_id,
1100 struct tsocket_address *dest,
1102 struct netlogon_samlogon_response *netlogon)
1105 struct cldap_reply reply;
1106 struct ldap_SearchResEntry response;
1107 struct ldap_Result result;
1108 TALLOC_CTX *tmp_ctx = talloc_new(cldap);
1111 status = push_netlogon_samlogon_response(&blob, tmp_ctx,
1113 if (!NT_STATUS_IS_OK(status)) {
1114 talloc_free(tmp_ctx);
1117 reply.messageid = message_id;
1119 reply.response = &response;
1120 reply.result = &result;
1122 ZERO_STRUCT(result);
1125 response.num_attributes = 1;
1126 response.attributes = talloc(tmp_ctx, struct ldb_message_element);
1127 NT_STATUS_HAVE_NO_MEMORY(response.attributes);
1128 response.attributes->name = "netlogon";
1129 response.attributes->num_values = 1;
1130 response.attributes->values = &blob;
1132 status = cldap_reply_send(cldap, &reply);
1134 talloc_free(tmp_ctx);