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.
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;
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;
78 /* what to do with incoming request packets */
80 struct tevent_context *ev;
81 void (*handler)(struct cldap_socket *,
83 struct cldap_incoming *);
88 struct cldap_search_state {
89 struct cldap_search_state *prev, *next;
92 struct tevent_context *ev;
93 struct cldap_socket *cldap;
102 struct tsocket_address *dest;
107 struct cldap_incoming *in;
108 struct asn1_data *asn1;
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);
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) {
138 if (!c->searches.list && !c->incoming.handler) {
144 ev = c->searches.list->caller.ev;
147 c->recv_subreq = tdgram_recvfrom_send(c, ev, 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_common(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 const struct tsocket_address *local_addr,
308 const struct tsocket_address *remote_addr,
309 struct cldap_socket **_cldap)
311 struct cldap_socket *c = NULL;
312 struct tsocket_address *any = NULL;
316 c = talloc_zero(mem_ctx, struct cldap_socket);
322 /* we use ipv4 here instead of ip, as otherwise we end
323 up with a PF_INET6 socket, and sendto() for ipv4
324 addresses will fail. That breaks cldap name
325 resolution for winbind to IPv4 hosts. */
326 ret = tsocket_address_inet_from_strings(c, "ipv4",
330 status = map_nt_error_from_unix_common(errno);
336 c->searches.idr = idr_init(c);
337 if (!c->searches.idr) {
341 ret = tdgram_inet_udp_socket(local_addr, remote_addr,
344 status = map_nt_error_from_unix_common(errno);
353 c->send_queue = tevent_queue_create(c, "cldap_send_queue");
354 if (!c->send_queue) {
358 talloc_set_destructor(c, cldap_socket_destructor);
364 status = NT_STATUS_NO_MEMORY;
371 setup a handler for incoming requests
373 NTSTATUS cldap_set_incoming_handler(struct cldap_socket *c,
374 struct tevent_context *ev,
375 void (*handler)(struct cldap_socket *,
377 struct cldap_incoming *),
381 return NT_STATUS_PIPE_CONNECTED;
385 c->incoming.handler = handler;
386 c->incoming.private_data = private_data;
388 if (!cldap_recvfrom_setup(c)) {
389 ZERO_STRUCT(c->incoming);
390 return NT_STATUS_NO_MEMORY;
396 struct cldap_reply_state {
397 struct tsocket_address *dest;
401 static void cldap_reply_state_destroy(struct tevent_req *subreq);
404 queue a cldap reply for send
406 NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
408 struct cldap_reply_state *state = NULL;
409 struct ldap_message *msg;
410 DATA_BLOB blob1, blob2;
412 struct tevent_req *subreq;
414 if (cldap->connected) {
415 return NT_STATUS_PIPE_CONNECTED;
418 if (cldap->incoming.ev == NULL) {
419 return NT_STATUS_INVALID_PIPE_STATE;
423 return NT_STATUS_INVALID_ADDRESS;
426 state = talloc(cldap, struct cldap_reply_state);
427 NT_STATUS_HAVE_NO_MEMORY(state);
429 state->dest = tsocket_address_copy(io->dest, state);
434 msg = talloc(state, struct ldap_message);
439 msg->messageid = io->messageid;
440 msg->controls = NULL;
443 msg->type = LDAP_TAG_SearchResultEntry;
444 msg->r.SearchResultEntry = *io->response;
446 if (!ldap_encode(msg, NULL, &blob1, state)) {
447 status = NT_STATUS_INVALID_PARAMETER;
451 blob1 = data_blob(NULL, 0);
454 msg->type = LDAP_TAG_SearchResultDone;
455 msg->r.SearchResultDone = *io->result;
457 if (!ldap_encode(msg, NULL, &blob2, state)) {
458 status = NT_STATUS_INVALID_PARAMETER;
463 state->blob = data_blob_talloc(state, NULL, blob1.length + blob2.length);
464 if (!state->blob.data) {
468 memcpy(state->blob.data, blob1.data, blob1.length);
469 memcpy(state->blob.data+blob1.length, blob2.data, blob2.length);
470 data_blob_free(&blob1);
471 data_blob_free(&blob2);
473 subreq = tdgram_sendto_queue_send(state,
483 /* the callback will just free the state, as we don't need a result */
484 tevent_req_set_callback(subreq, cldap_reply_state_destroy, state);
489 status = NT_STATUS_NO_MEMORY;
495 static void cldap_reply_state_destroy(struct tevent_req *subreq)
497 struct cldap_reply_state *state = tevent_req_callback_data(subreq,
498 struct cldap_reply_state);
500 /* we don't want to know the result here, we just free the state */
505 static int cldap_search_state_destructor(struct cldap_search_state *s)
507 if (s->caller.cldap) {
508 if (s->message_id != -1) {
509 idr_remove(s->caller.cldap->searches.idr, s->message_id);
512 DLIST_REMOVE(s->caller.cldap->searches.list, s);
513 cldap_recvfrom_stop(s->caller.cldap);
514 ZERO_STRUCT(s->caller);
520 static void cldap_search_state_queue_done(struct tevent_req *subreq);
521 static void cldap_search_state_wakeup_done(struct tevent_req *subreq);
524 queue a cldap reply for send
526 struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
527 struct tevent_context *ev,
528 struct cldap_socket *cldap,
529 const struct cldap_search *io)
531 struct tevent_req *req, *subreq;
532 struct cldap_search_state *state = NULL;
533 struct ldap_message *msg;
534 struct ldap_SearchRequest *search;
540 req = tevent_req_create(mem_ctx, &state,
541 struct cldap_search_state);
546 state->caller.ev = ev;
548 state->caller.cldap = cldap;
549 state->message_id = -1;
551 talloc_set_destructor(state, cldap_search_state_destructor);
553 if (io->in.dest_address) {
554 if (cldap->connected) {
555 tevent_req_nterror(req, NT_STATUS_PIPE_CONNECTED);
558 ret = tsocket_address_inet_from_strings(state,
562 &state->request.dest);
564 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
568 if (!cldap->connected) {
569 tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
572 state->request.dest = NULL;
575 state->message_id = idr_get_new_random(cldap->searches.idr,
577 if (state->message_id == -1) {
578 tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
582 msg = talloc(state, struct ldap_message);
583 if (tevent_req_nomem(msg, req)) {
587 msg->messageid = state->message_id;
588 msg->type = LDAP_TAG_SearchRequest;
589 msg->controls = NULL;
590 search = &msg->r.SearchRequest;
593 search->scope = LDAP_SEARCH_SCOPE_BASE;
594 search->deref = LDAP_DEREFERENCE_NEVER;
595 search->timelimit = 0;
596 search->sizelimit = 0;
597 search->attributesonly = false;
598 search->num_attributes = str_list_length(io->in.attributes);
599 search->attributes = io->in.attributes;
600 search->tree = ldb_parse_tree(msg, io->in.filter);
601 if (tevent_req_nomem(search->tree, req)) {
605 if (!ldap_encode(msg, NULL, &state->request.blob, state)) {
606 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
611 state->request.idx = 0;
612 state->request.delay = 10*1000*1000;
613 state->request.count = 3;
614 if (io->in.timeout > 0) {
615 state->request.delay = io->in.timeout * 1000 * 1000;
616 state->request.count = io->in.retries + 1;
619 now = tevent_timeval_current();
621 for (i = 0; i < state->request.count; i++) {
622 end = tevent_timeval_add(&end, state->request.delay / 1000000,
623 state->request.delay % 1000000);
626 if (!tevent_req_set_endtime(req, state->caller.ev, end)) {
631 subreq = tdgram_sendto_queue_send(state,
633 state->caller.cldap->sock,
634 state->caller.cldap->send_queue,
635 state->request.blob.data,
636 state->request.blob.length,
637 state->request.dest);
638 if (tevent_req_nomem(subreq, req)) {
641 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
643 DLIST_ADD_END(cldap->searches.list, state, struct cldap_search_state *);
648 return tevent_req_post(req, state->caller.ev);
651 static void cldap_search_state_queue_done(struct tevent_req *subreq)
653 struct tevent_req *req = tevent_req_callback_data(subreq,
655 struct cldap_search_state *state = tevent_req_data(req,
656 struct cldap_search_state);
661 ret = tdgram_sendto_queue_recv(subreq, &sys_errno);
665 status = map_nt_error_from_unix_common(sys_errno);
666 DLIST_REMOVE(state->caller.cldap->searches.list, state);
667 ZERO_STRUCT(state->caller.cldap);
668 tevent_req_nterror(req, status);
672 state->request.idx++;
674 /* wait for incoming traffic */
675 if (!cldap_recvfrom_setup(state->caller.cldap)) {
680 if (state->request.idx > state->request.count) {
681 /* we just wait for the response or a timeout */
685 next = tevent_timeval_current_ofs(state->request.delay / 1000000,
686 state->request.delay % 1000000);
687 subreq = tevent_wakeup_send(state,
690 if (tevent_req_nomem(subreq, req)) {
693 tevent_req_set_callback(subreq, cldap_search_state_wakeup_done, req);
696 static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
698 struct tevent_req *req = tevent_req_callback_data(subreq,
700 struct cldap_search_state *state = tevent_req_data(req,
701 struct cldap_search_state);
704 ok = tevent_wakeup_recv(subreq);
707 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
711 subreq = tdgram_sendto_queue_send(state,
713 state->caller.cldap->sock,
714 state->caller.cldap->send_queue,
715 state->request.blob.data,
716 state->request.blob.length,
717 state->request.dest);
718 if (tevent_req_nomem(subreq, req)) {
721 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
725 receive a cldap reply
727 NTSTATUS cldap_search_recv(struct tevent_req *req,
729 struct cldap_search *io)
731 struct cldap_search_state *state = tevent_req_data(req,
732 struct cldap_search_state);
733 struct ldap_message *ldap_msg;
736 if (tevent_req_is_nterror(req, &status)) {
740 ldap_msg = talloc(mem_ctx, struct ldap_message);
745 status = ldap_decode(state->response.asn1, NULL, ldap_msg);
746 if (!NT_STATUS_IS_OK(status)) {
750 ZERO_STRUCT(io->out);
752 /* the first possible form has a search result in first place */
753 if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
754 io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
755 if (!io->out.response) {
758 *io->out.response = ldap_msg->r.SearchResultEntry;
760 /* decode the 2nd part */
761 status = ldap_decode(state->response.asn1, NULL, ldap_msg);
762 if (!NT_STATUS_IS_OK(status)) {
767 if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
768 status = NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
772 io->out.result = talloc(mem_ctx, struct ldap_Result);
773 if (!io->out.result) {
776 *io->out.result = ldap_msg->r.SearchResultDone;
778 if (io->out.result->resultcode != LDAP_SUCCESS) {
779 status = NT_STATUS_LDAP(io->out.result->resultcode);
783 tevent_req_received(req);
787 status = NT_STATUS_NO_MEMORY;
789 tevent_req_received(req);
795 synchronous cldap search
797 NTSTATUS cldap_search(struct cldap_socket *cldap,
799 struct cldap_search *io)
802 struct tevent_req *req;
803 struct tevent_context *ev;
806 if (cldap->searches.list) {
807 return NT_STATUS_PIPE_BUSY;
810 if (cldap->incoming.handler) {
811 return NT_STATUS_INVALID_PIPE_STATE;
814 frame = talloc_stackframe();
816 ev = tevent_context_init(frame);
819 return NT_STATUS_NO_MEMORY;
822 req = cldap_search_send(mem_ctx, ev, cldap, io);
825 return NT_STATUS_NO_MEMORY;
828 if (!tevent_req_poll(req, ev)) {
829 status = map_nt_error_from_unix_common(errno);
834 status = cldap_search_recv(req, mem_ctx, io);
835 if (!NT_STATUS_IS_OK(status)) {
844 struct cldap_netlogon_state {
845 struct cldap_search search;
848 static void cldap_netlogon_state_done(struct tevent_req *subreq);
850 queue a cldap netlogon for send
852 struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
853 struct tevent_context *ev,
854 struct cldap_socket *cldap,
855 const struct cldap_netlogon *io)
857 struct tevent_req *req, *subreq;
858 struct cldap_netlogon_state *state;
860 static const char * const attr[] = { "NetLogon", NULL };
862 req = tevent_req_create(mem_ctx, &state,
863 struct cldap_netlogon_state);
868 filter = talloc_asprintf(state, "(&(NtVer=%s)",
869 ldap_encode_ndr_uint32(state, io->in.version));
870 if (tevent_req_nomem(filter, req)) {
874 filter = talloc_asprintf_append_buffer(filter, "(User=%s)", io->in.user);
875 if (tevent_req_nomem(filter, req)) {
880 filter = talloc_asprintf_append_buffer(filter, "(Host=%s)", io->in.host);
881 if (tevent_req_nomem(filter, req)) {
886 filter = talloc_asprintf_append_buffer(filter, "(DnsDomain=%s)", io->in.realm);
887 if (tevent_req_nomem(filter, req)) {
891 if (io->in.acct_control != -1) {
892 filter = talloc_asprintf_append_buffer(filter, "(AAC=%s)",
893 ldap_encode_ndr_uint32(state, io->in.acct_control));
894 if (tevent_req_nomem(filter, req)) {
898 if (io->in.domain_sid) {
899 struct dom_sid *sid = dom_sid_parse_talloc(state, io->in.domain_sid);
900 if (tevent_req_nomem(sid, req)) {
903 filter = talloc_asprintf_append_buffer(filter, "(domainSid=%s)",
904 ldap_encode_ndr_dom_sid(state, sid));
905 if (tevent_req_nomem(filter, req)) {
909 if (io->in.domain_guid) {
912 status = GUID_from_string(io->in.domain_guid, &guid);
913 if (tevent_req_nterror(req, status)) {
916 filter = talloc_asprintf_append_buffer(filter, "(DomainGuid=%s)",
917 ldap_encode_ndr_GUID(state, &guid));
918 if (tevent_req_nomem(filter, req)) {
922 filter = talloc_asprintf_append_buffer(filter, ")");
923 if (tevent_req_nomem(filter, req)) {
927 if (io->in.dest_address) {
928 state->search.in.dest_address = talloc_strdup(state,
929 io->in.dest_address);
930 if (tevent_req_nomem(state->search.in.dest_address, req)) {
933 state->search.in.dest_port = io->in.dest_port;
935 state->search.in.dest_address = NULL;
936 state->search.in.dest_port = 0;
938 state->search.in.filter = filter;
939 state->search.in.attributes = attr;
940 state->search.in.timeout = 2;
941 state->search.in.retries = 2;
943 subreq = cldap_search_send(state, ev, cldap, &state->search);
944 if (tevent_req_nomem(subreq, req)) {
947 tevent_req_set_callback(subreq, cldap_netlogon_state_done, req);
951 return tevent_req_post(req, ev);
954 static void cldap_netlogon_state_done(struct tevent_req *subreq)
956 struct tevent_req *req = tevent_req_callback_data(subreq,
958 struct cldap_netlogon_state *state = tevent_req_data(req,
959 struct cldap_netlogon_state);
962 status = cldap_search_recv(subreq, state, &state->search);
965 if (tevent_req_nterror(req, status)) {
969 tevent_req_done(req);
973 receive a cldap netlogon reply
975 NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
977 struct cldap_netlogon *io)
979 struct cldap_netlogon_state *state = tevent_req_data(req,
980 struct cldap_netlogon_state);
984 if (tevent_req_is_nterror(req, &status)) {
988 if (state->search.out.response == NULL) {
989 status = NT_STATUS_NOT_FOUND;
993 if (state->search.out.response->num_attributes != 1 ||
994 strcasecmp(state->search.out.response->attributes[0].name, "netlogon") != 0 ||
995 state->search.out.response->attributes[0].num_values != 1 ||
996 state->search.out.response->attributes[0].values->length < 2) {
997 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1000 data = state->search.out.response->attributes[0].values;
1002 status = pull_netlogon_samlogon_response(data, mem_ctx,
1004 if (!NT_STATUS_IS_OK(status)) {
1008 if (io->in.map_response) {
1009 map_netlogon_samlogon_response(&io->out.netlogon);
1012 status = NT_STATUS_OK;
1014 tevent_req_received(req);
1019 sync cldap netlogon search
1021 NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
1022 TALLOC_CTX *mem_ctx,
1023 struct cldap_netlogon *io)
1026 struct tevent_req *req;
1027 struct tevent_context *ev;
1030 if (cldap->searches.list) {
1031 return NT_STATUS_PIPE_BUSY;
1034 if (cldap->incoming.handler) {
1035 return NT_STATUS_INVALID_PIPE_STATE;
1038 frame = talloc_stackframe();
1040 ev = tevent_context_init(frame);
1043 return NT_STATUS_NO_MEMORY;
1046 req = cldap_netlogon_send(mem_ctx, ev, cldap, io);
1049 return NT_STATUS_NO_MEMORY;
1052 if (!tevent_req_poll(req, ev)) {
1053 status = map_nt_error_from_unix_common(errno);
1058 status = cldap_netlogon_recv(req, mem_ctx, io);
1059 if (!NT_STATUS_IS_OK(status)) {
1065 return NT_STATUS_OK;
1070 send an empty reply (used on any error, so the client doesn't keep waiting
1071 or send the bad request again)
1073 NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
1074 uint32_t message_id,
1075 struct tsocket_address *dest)
1078 struct cldap_reply reply;
1079 struct ldap_Result result;
1081 reply.messageid = message_id;
1083 reply.response = NULL;
1084 reply.result = &result;
1086 ZERO_STRUCT(result);
1088 status = cldap_reply_send(cldap, &reply);
1094 send an error reply (used on any error, so the client doesn't keep waiting
1095 or send the bad request again)
1097 NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
1098 uint32_t message_id,
1099 struct tsocket_address *dest,
1101 const char *errormessage)
1104 struct cldap_reply reply;
1105 struct ldap_Result result;
1107 reply.messageid = message_id;
1109 reply.response = NULL;
1110 reply.result = &result;
1112 ZERO_STRUCT(result);
1113 result.resultcode = resultcode;
1114 result.errormessage = errormessage;
1116 status = cldap_reply_send(cldap, &reply);
1123 send a netlogon reply
1125 NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
1126 uint32_t message_id,
1127 struct tsocket_address *dest,
1129 struct netlogon_samlogon_response *netlogon)
1132 struct cldap_reply reply;
1133 struct ldap_SearchResEntry response;
1134 struct ldap_Result result;
1135 TALLOC_CTX *tmp_ctx = talloc_new(cldap);
1138 status = push_netlogon_samlogon_response(&blob, tmp_ctx,
1140 if (!NT_STATUS_IS_OK(status)) {
1141 talloc_free(tmp_ctx);
1144 reply.messageid = message_id;
1146 reply.response = &response;
1147 reply.result = &result;
1149 ZERO_STRUCT(result);
1152 response.num_attributes = 1;
1153 response.attributes = talloc(tmp_ctx, struct ldb_message_element);
1154 NT_STATUS_HAVE_NO_MEMORY(response.attributes);
1155 response.attributes->name = "netlogon";
1156 response.attributes->num_values = 1;
1157 response.attributes->values = &blob;
1159 status = cldap_reply_send(cldap, &reply);
1161 talloc_free(tmp_ctx);