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 void (*handler)(struct cldap_socket *,
91 struct cldap_incoming *);
96 struct cldap_search_state {
97 struct cldap_search_state *prev, *next;
100 struct cldap_socket *cldap;
109 struct tsocket_address *dest;
114 struct cldap_incoming *in;
115 struct asn1_data *asn1;
118 struct tevent_req *req;
121 static int cldap_socket_destructor(struct cldap_socket *c)
123 while (c->searches.list) {
124 struct cldap_search_state *s = c->searches.list;
125 DLIST_REMOVE(c->searches.list, s);
126 ZERO_STRUCT(s->caller);
129 talloc_free(c->recv_subreq);
130 talloc_free(c->send_queue);
131 talloc_free(c->sock);
135 static void cldap_recvfrom_done(struct tevent_req *subreq);
137 static bool cldap_recvfrom_setup(struct cldap_socket *c)
139 if (c->recv_subreq) {
143 if (!c->searches.list && !c->incoming.handler) {
147 c->recv_subreq = tdgram_recvfrom_send(c, c->event.ctx, c->sock);
148 if (!c->recv_subreq) {
151 tevent_req_set_callback(c->recv_subreq, cldap_recvfrom_done, c);
156 static void cldap_recvfrom_stop(struct cldap_socket *c)
158 if (!c->recv_subreq) {
162 if (c->searches.list || c->incoming.handler) {
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;
181 c->recv_subreq = NULL;
183 in = talloc_zero(c, struct cldap_incoming);
188 ret = tdgram_recvfrom_recv(subreq,
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);
206 if (!setup_done && !cldap_recvfrom_setup(c)) {
215 /*TODO: call a dead socket handler */
220 handle recv events on a cldap socket
222 static bool cldap_socket_recv_dgram(struct cldap_socket *c,
223 struct cldap_incoming *in)
226 struct asn1_data *asn1;
228 struct cldap_search_state *search;
231 if (in->recv_errno != 0) {
235 blob = data_blob_const(in->buf, in->len);
237 asn1 = asn1_init(in);
242 if (!asn1_load(asn1, blob)) {
246 in->ldap_msg = talloc(in, struct ldap_message);
247 if (in->ldap_msg == NULL) {
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)) {
257 /* find the pending request */
258 p = idr_find(c->searches.idr, in->ldap_msg->messageid);
260 if (!c->incoming.handler) {
264 /* this function should free or steal 'in' */
265 c->incoming.handler(c, c->incoming.private_data, in);
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)) {
280 tevent_req_done(search->req);
285 in->recv_errno = ENOMEM;
287 status = map_nt_error_from_unix(in->recv_errno);
289 /* in connected mode the first pending search gets the error */
291 /* otherwise we just ignore the error */
294 if (!c->searches.list) {
297 tevent_req_nterror(c->searches.list->req, status);
304 initialise a cldap_sock
306 NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx,
307 struct tevent_context *ev,
308 const struct tsocket_address *local_addr,
309 const struct tsocket_address *remote_addr,
310 struct cldap_socket **_cldap)
312 struct cldap_socket *c = NULL;
313 struct tsocket_address *any = NULL;
317 c = talloc_zero(mem_ctx, struct cldap_socket);
323 ev = tevent_context_init(c);
327 c->event.allow_poll = true;
332 /* we use ipv4 here instead of ip, as otherwise we end
333 up with a PF_INET6 socket, and sendto() for ipv4
334 addresses will fail. That breaks cldap name
335 resolution for winbind to IPv4 hosts. */
336 ret = tsocket_address_inet_from_strings(c, "ipv4",
340 status = map_nt_error_from_unix(errno);
346 c->searches.idr = idr_init(c);
347 if (!c->searches.idr) {
351 ret = tdgram_inet_udp_socket(local_addr, remote_addr,
354 status = map_nt_error_from_unix(errno);
363 c->send_queue = tevent_queue_create(c, "cldap_send_queue");
364 if (!c->send_queue) {
368 talloc_set_destructor(c, cldap_socket_destructor);
374 status = NT_STATUS_NO_MEMORY;
381 setup a handler for incoming requests
383 NTSTATUS cldap_set_incoming_handler(struct cldap_socket *c,
384 void (*handler)(struct cldap_socket *,
386 struct cldap_incoming *),
390 return NT_STATUS_PIPE_CONNECTED;
393 /* if sync requests are allowed, we don't allow an incoming handler */
394 if (c->event.allow_poll) {
395 return NT_STATUS_INVALID_PIPE_STATE;
398 c->incoming.handler = handler;
399 c->incoming.private_data = private_data;
401 if (!cldap_recvfrom_setup(c)) {
402 ZERO_STRUCT(c->incoming);
403 return NT_STATUS_NO_MEMORY;
409 struct cldap_reply_state {
410 struct tsocket_address *dest;
414 static void cldap_reply_state_destroy(struct tevent_req *subreq);
417 queue a cldap reply for send
419 NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
421 struct cldap_reply_state *state = NULL;
422 struct ldap_message *msg;
423 DATA_BLOB blob1, blob2;
425 struct tevent_req *subreq;
427 if (cldap->connected) {
428 return NT_STATUS_PIPE_CONNECTED;
432 return NT_STATUS_INVALID_ADDRESS;
435 state = talloc(cldap, struct cldap_reply_state);
436 NT_STATUS_HAVE_NO_MEMORY(state);
438 state->dest = tsocket_address_copy(io->dest, state);
443 msg = talloc(state, struct ldap_message);
448 msg->messageid = io->messageid;
449 msg->controls = NULL;
452 msg->type = LDAP_TAG_SearchResultEntry;
453 msg->r.SearchResultEntry = *io->response;
455 if (!ldap_encode(msg, NULL, &blob1, state)) {
456 status = NT_STATUS_INVALID_PARAMETER;
460 blob1 = data_blob(NULL, 0);
463 msg->type = LDAP_TAG_SearchResultDone;
464 msg->r.SearchResultDone = *io->result;
466 if (!ldap_encode(msg, NULL, &blob2, state)) {
467 status = NT_STATUS_INVALID_PARAMETER;
472 state->blob = data_blob_talloc(state, NULL, blob1.length + blob2.length);
473 if (!state->blob.data) {
477 memcpy(state->blob.data, blob1.data, blob1.length);
478 memcpy(state->blob.data+blob1.length, blob2.data, blob2.length);
479 data_blob_free(&blob1);
480 data_blob_free(&blob2);
482 subreq = tdgram_sendto_queue_send(state,
492 /* the callback will just free the state, as we don't need a result */
493 tevent_req_set_callback(subreq, cldap_reply_state_destroy, state);
498 status = NT_STATUS_NO_MEMORY;
504 static void cldap_reply_state_destroy(struct tevent_req *subreq)
506 struct cldap_reply_state *state = tevent_req_callback_data(subreq,
507 struct cldap_reply_state);
509 /* we don't want to know the result here, we just free the state */
514 static int cldap_search_state_destructor(struct cldap_search_state *s)
516 if (s->caller.cldap) {
517 if (s->message_id != -1) {
518 idr_remove(s->caller.cldap->searches.idr, s->message_id);
521 DLIST_REMOVE(s->caller.cldap->searches.list, s);
522 cldap_recvfrom_stop(s->caller.cldap);
523 ZERO_STRUCT(s->caller);
529 static void cldap_search_state_queue_done(struct tevent_req *subreq);
530 static void cldap_search_state_wakeup_done(struct tevent_req *subreq);
533 queue a cldap reply for send
535 struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
536 struct cldap_socket *cldap,
537 const struct cldap_search *io)
539 struct tevent_req *req, *subreq;
540 struct cldap_search_state *state = NULL;
541 struct ldap_message *msg;
542 struct ldap_SearchRequest *search;
548 req = tevent_req_create(mem_ctx, &state,
549 struct cldap_search_state);
555 state->caller.cldap = cldap;
556 state->message_id = -1;
558 talloc_set_destructor(state, cldap_search_state_destructor);
560 if (io->in.dest_address) {
561 if (cldap->connected) {
562 tevent_req_nterror(req, NT_STATUS_PIPE_CONNECTED);
565 ret = tsocket_address_inet_from_strings(state,
569 &state->request.dest);
571 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
575 if (!cldap->connected) {
576 tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
579 state->request.dest = NULL;
582 state->message_id = idr_get_new_random(cldap->searches.idr,
584 if (state->message_id == -1) {
585 tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
589 msg = talloc(state, struct ldap_message);
590 if (tevent_req_nomem(msg, req)) {
594 msg->messageid = state->message_id;
595 msg->type = LDAP_TAG_SearchRequest;
596 msg->controls = NULL;
597 search = &msg->r.SearchRequest;
600 search->scope = LDAP_SEARCH_SCOPE_BASE;
601 search->deref = LDAP_DEREFERENCE_NEVER;
602 search->timelimit = 0;
603 search->sizelimit = 0;
604 search->attributesonly = false;
605 search->num_attributes = str_list_length(io->in.attributes);
606 search->attributes = io->in.attributes;
607 search->tree = ldb_parse_tree(msg, io->in.filter);
608 if (tevent_req_nomem(search->tree, req)) {
612 if (!ldap_encode(msg, NULL, &state->request.blob, state)) {
613 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
618 state->request.idx = 0;
619 state->request.delay = 10*1000*1000;
620 state->request.count = 3;
621 if (io->in.timeout > 0) {
622 state->request.delay = io->in.timeout * 1000 * 1000;
623 state->request.count = io->in.retries + 1;
626 now = tevent_timeval_current();
628 for (i = 0; i < state->request.count; i++) {
629 end = tevent_timeval_add(&end, 0, state->request.delay);
632 if (!tevent_req_set_endtime(req, state->caller.cldap->event.ctx, end)) {
633 tevent_req_nomem(NULL, req);
637 subreq = tdgram_sendto_queue_send(state,
638 state->caller.cldap->event.ctx,
639 state->caller.cldap->sock,
640 state->caller.cldap->send_queue,
641 state->request.blob.data,
642 state->request.blob.length,
643 state->request.dest);
644 if (tevent_req_nomem(subreq, req)) {
647 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
649 DLIST_ADD_END(cldap->searches.list, state, struct cldap_search_state *);
654 return tevent_req_post(req, cldap->event.ctx);
657 static void cldap_search_state_queue_done(struct tevent_req *subreq)
659 struct tevent_req *req = tevent_req_callback_data(subreq,
661 struct cldap_search_state *state = tevent_req_data(req,
662 struct cldap_search_state);
667 ret = tdgram_sendto_queue_recv(subreq, &sys_errno);
671 status = map_nt_error_from_unix(sys_errno);
672 DLIST_REMOVE(state->caller.cldap->searches.list, state);
673 ZERO_STRUCT(state->caller.cldap);
674 tevent_req_nterror(req, status);
678 state->request.idx++;
680 /* wait for incoming traffic */
681 if (!cldap_recvfrom_setup(state->caller.cldap)) {
682 tevent_req_nomem(NULL, req);
686 if (state->request.idx > state->request.count) {
687 /* we just wait for the response or a timeout */
691 next = tevent_timeval_current_ofs(0, state->request.delay);
692 subreq = tevent_wakeup_send(state,
693 state->caller.cldap->event.ctx,
695 if (tevent_req_nomem(subreq, req)) {
698 tevent_req_set_callback(subreq, cldap_search_state_wakeup_done, req);
701 static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
703 struct tevent_req *req = tevent_req_callback_data(subreq,
705 struct cldap_search_state *state = tevent_req_data(req,
706 struct cldap_search_state);
709 ok = tevent_wakeup_recv(subreq);
712 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
716 subreq = tdgram_sendto_queue_send(state,
717 state->caller.cldap->event.ctx,
718 state->caller.cldap->sock,
719 state->caller.cldap->send_queue,
720 state->request.blob.data,
721 state->request.blob.length,
722 state->request.dest);
723 if (tevent_req_nomem(subreq, req)) {
726 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
730 receive a cldap reply
732 NTSTATUS cldap_search_recv(struct tevent_req *req,
734 struct cldap_search *io)
736 struct cldap_search_state *state = tevent_req_data(req,
737 struct cldap_search_state);
738 struct ldap_message *ldap_msg;
741 if (tevent_req_is_nterror(req, &status)) {
745 ldap_msg = talloc(mem_ctx, struct ldap_message);
750 status = ldap_decode(state->response.asn1, NULL, ldap_msg);
751 if (!NT_STATUS_IS_OK(status)) {
755 ZERO_STRUCT(io->out);
757 /* the first possible form has a search result in first place */
758 if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
759 io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
760 if (!io->out.response) {
763 *io->out.response = ldap_msg->r.SearchResultEntry;
765 /* decode the 2nd part */
766 status = ldap_decode(state->response.asn1, NULL, ldap_msg);
767 if (!NT_STATUS_IS_OK(status)) {
772 if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
773 status = NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
777 io->out.result = talloc(mem_ctx, struct ldap_Result);
778 if (!io->out.result) {
781 *io->out.result = ldap_msg->r.SearchResultDone;
783 if (io->out.result->resultcode != LDAP_SUCCESS) {
784 status = NT_STATUS_LDAP(io->out.result->resultcode);
788 tevent_req_received(req);
792 status = NT_STATUS_NO_MEMORY;
794 tevent_req_received(req);
800 synchronous cldap search
802 NTSTATUS cldap_search(struct cldap_socket *cldap,
804 struct cldap_search *io)
806 struct tevent_req *req;
809 if (!cldap->event.allow_poll) {
810 return NT_STATUS_INVALID_PIPE_STATE;
813 if (cldap->searches.list) {
814 return NT_STATUS_PIPE_BUSY;
817 req = cldap_search_send(mem_ctx, cldap, io);
818 NT_STATUS_HAVE_NO_MEMORY(req);
820 if (!tevent_req_poll(req, cldap->event.ctx)) {
822 return NT_STATUS_INTERNAL_ERROR;
825 status = cldap_search_recv(req, mem_ctx, io);
831 struct cldap_netlogon_state {
832 struct cldap_search search;
835 static void cldap_netlogon_state_done(struct tevent_req *subreq);
837 queue a cldap netlogon for send
839 struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
840 struct cldap_socket *cldap,
841 const struct cldap_netlogon *io)
843 struct tevent_req *req, *subreq;
844 struct cldap_netlogon_state *state;
846 static const char * const attr[] = { "NetLogon", NULL };
848 req = tevent_req_create(mem_ctx, &state,
849 struct cldap_netlogon_state);
854 filter = talloc_asprintf(state, "(&(NtVer=%s)",
855 ldap_encode_ndr_uint32(state, io->in.version));
856 if (tevent_req_nomem(filter, req)) {
860 filter = talloc_asprintf_append_buffer(filter, "(User=%s)", io->in.user);
861 if (tevent_req_nomem(filter, req)) {
866 filter = talloc_asprintf_append_buffer(filter, "(Host=%s)", io->in.host);
867 if (tevent_req_nomem(filter, req)) {
872 filter = talloc_asprintf_append_buffer(filter, "(DnsDomain=%s)", io->in.realm);
873 if (tevent_req_nomem(filter, req)) {
877 if (io->in.acct_control != -1) {
878 filter = talloc_asprintf_append_buffer(filter, "(AAC=%s)",
879 ldap_encode_ndr_uint32(state, io->in.acct_control));
880 if (tevent_req_nomem(filter, req)) {
884 if (io->in.domain_sid) {
885 struct dom_sid *sid = dom_sid_parse_talloc(state, io->in.domain_sid);
886 if (tevent_req_nomem(sid, req)) {
889 filter = talloc_asprintf_append_buffer(filter, "(domainSid=%s)",
890 ldap_encode_ndr_dom_sid(state, sid));
891 if (tevent_req_nomem(filter, req)) {
895 if (io->in.domain_guid) {
898 status = GUID_from_string(io->in.domain_guid, &guid);
899 if (tevent_req_nterror(req, status)) {
902 filter = talloc_asprintf_append_buffer(filter, "(DomainGuid=%s)",
903 ldap_encode_ndr_GUID(state, &guid));
904 if (tevent_req_nomem(filter, req)) {
908 filter = talloc_asprintf_append_buffer(filter, ")");
909 if (tevent_req_nomem(filter, req)) {
913 if (io->in.dest_address) {
914 state->search.in.dest_address = talloc_strdup(state,
915 io->in.dest_address);
916 if (tevent_req_nomem(state->search.in.dest_address, req)) {
919 state->search.in.dest_port = io->in.dest_port;
921 state->search.in.dest_address = NULL;
922 state->search.in.dest_port = 0;
924 state->search.in.filter = filter;
925 state->search.in.attributes = attr;
926 state->search.in.timeout = 2;
927 state->search.in.retries = 2;
929 subreq = cldap_search_send(state, cldap, &state->search);
930 if (tevent_req_nomem(subreq, req)) {
933 tevent_req_set_callback(subreq, cldap_netlogon_state_done, req);
937 return tevent_req_post(req, cldap->event.ctx);
940 static void cldap_netlogon_state_done(struct tevent_req *subreq)
942 struct tevent_req *req = tevent_req_callback_data(subreq,
944 struct cldap_netlogon_state *state = tevent_req_data(req,
945 struct cldap_netlogon_state);
948 status = cldap_search_recv(subreq, state, &state->search);
951 if (tevent_req_nterror(req, status)) {
955 tevent_req_done(req);
959 receive a cldap netlogon reply
961 NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
963 struct cldap_netlogon *io)
965 struct cldap_netlogon_state *state = tevent_req_data(req,
966 struct cldap_netlogon_state);
970 if (tevent_req_is_nterror(req, &status)) {
974 if (state->search.out.response == NULL) {
975 status = NT_STATUS_NOT_FOUND;
979 if (state->search.out.response->num_attributes != 1 ||
980 strcasecmp(state->search.out.response->attributes[0].name, "netlogon") != 0 ||
981 state->search.out.response->attributes[0].num_values != 1 ||
982 state->search.out.response->attributes[0].values->length < 2) {
983 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
986 data = state->search.out.response->attributes[0].values;
988 status = pull_netlogon_samlogon_response(data, mem_ctx,
990 if (!NT_STATUS_IS_OK(status)) {
994 if (io->in.map_response) {
995 map_netlogon_samlogon_response(&io->out.netlogon);
998 status = NT_STATUS_OK;
1000 tevent_req_received(req);
1005 sync cldap netlogon search
1007 NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
1008 TALLOC_CTX *mem_ctx,
1009 struct cldap_netlogon *io)
1011 struct tevent_req *req;
1014 if (!cldap->event.allow_poll) {
1015 return NT_STATUS_INVALID_PIPE_STATE;
1018 if (cldap->searches.list) {
1019 return NT_STATUS_PIPE_BUSY;
1022 req = cldap_netlogon_send(mem_ctx, cldap, io);
1023 NT_STATUS_HAVE_NO_MEMORY(req);
1025 if (!tevent_req_poll(req, cldap->event.ctx)) {
1027 return NT_STATUS_INTERNAL_ERROR;
1030 status = cldap_netlogon_recv(req, mem_ctx, io);
1038 send an empty reply (used on any error, so the client doesn't keep waiting
1039 or send the bad request again)
1041 NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
1042 uint32_t message_id,
1043 struct tsocket_address *dest)
1046 struct cldap_reply reply;
1047 struct ldap_Result result;
1049 reply.messageid = message_id;
1051 reply.response = NULL;
1052 reply.result = &result;
1054 ZERO_STRUCT(result);
1056 status = cldap_reply_send(cldap, &reply);
1062 send an error reply (used on any error, so the client doesn't keep waiting
1063 or send the bad request again)
1065 NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
1066 uint32_t message_id,
1067 struct tsocket_address *dest,
1069 const char *errormessage)
1072 struct cldap_reply reply;
1073 struct ldap_Result result;
1075 reply.messageid = message_id;
1077 reply.response = NULL;
1078 reply.result = &result;
1080 ZERO_STRUCT(result);
1081 result.resultcode = resultcode;
1082 result.errormessage = errormessage;
1084 status = cldap_reply_send(cldap, &reply);
1091 send a netlogon reply
1093 NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
1094 uint32_t message_id,
1095 struct tsocket_address *dest,
1097 struct netlogon_samlogon_response *netlogon)
1100 struct cldap_reply reply;
1101 struct ldap_SearchResEntry response;
1102 struct ldap_Result result;
1103 TALLOC_CTX *tmp_ctx = talloc_new(cldap);
1106 status = push_netlogon_samlogon_response(&blob, tmp_ctx,
1108 if (!NT_STATUS_IS_OK(status)) {
1109 talloc_free(tmp_ctx);
1112 reply.messageid = message_id;
1114 reply.response = &response;
1115 reply.result = &result;
1117 ZERO_STRUCT(result);
1120 response.num_attributes = 1;
1121 response.attributes = talloc(tmp_ctx, struct ldb_message_element);
1122 NT_STATUS_HAVE_NO_MEMORY(response.attributes);
1123 response.attributes->name = "netlogon";
1124 response.attributes->num_values = 1;
1125 response.attributes->values = &blob;
1127 status = cldap_reply_send(cldap, &reply);
1129 talloc_free(tmp_ctx);