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 tevent_context *ev;
102 struct cldap_socket *cldap;
111 struct tsocket_address *dest;
116 struct cldap_incoming *in;
117 struct asn1_data *asn1;
120 struct tevent_req *req;
123 static int cldap_socket_destructor(struct cldap_socket *c)
125 while (c->searches.list) {
126 struct cldap_search_state *s = c->searches.list;
127 DLIST_REMOVE(c->searches.list, s);
128 ZERO_STRUCT(s->caller);
131 talloc_free(c->recv_subreq);
132 talloc_free(c->send_queue);
133 talloc_free(c->sock);
137 static void cldap_recvfrom_done(struct tevent_req *subreq);
139 static bool cldap_recvfrom_setup(struct cldap_socket *c)
141 if (c->recv_subreq) {
145 if (!c->searches.list && !c->incoming.handler) {
149 c->recv_subreq = tdgram_recvfrom_send(c, c->event.ctx, c->sock);
150 if (!c->recv_subreq) {
153 tevent_req_set_callback(c->recv_subreq, cldap_recvfrom_done, c);
158 static void cldap_recvfrom_stop(struct cldap_socket *c)
160 if (!c->recv_subreq) {
164 if (c->searches.list || c->incoming.handler) {
168 talloc_free(c->recv_subreq);
169 c->recv_subreq = NULL;
172 static bool cldap_socket_recv_dgram(struct cldap_socket *c,
173 struct cldap_incoming *in);
175 static void cldap_recvfrom_done(struct tevent_req *subreq)
177 struct cldap_socket *c = tevent_req_callback_data(subreq,
178 struct cldap_socket);
179 struct cldap_incoming *in = NULL;
183 c->recv_subreq = NULL;
185 in = talloc_zero(c, struct cldap_incoming);
190 ret = tdgram_recvfrom_recv(subreq,
200 if (ret == -1 && in->recv_errno == 0) {
201 in->recv_errno = EIO;
204 /* this function should free or steal 'in' */
205 setup_done = cldap_socket_recv_dgram(c, in);
208 if (!setup_done && !cldap_recvfrom_setup(c)) {
217 /*TODO: call a dead socket handler */
222 handle recv events on a cldap socket
224 static bool cldap_socket_recv_dgram(struct cldap_socket *c,
225 struct cldap_incoming *in)
228 struct asn1_data *asn1;
230 struct cldap_search_state *search;
233 if (in->recv_errno != 0) {
237 blob = data_blob_const(in->buf, in->len);
239 asn1 = asn1_init(in);
244 if (!asn1_load(asn1, blob)) {
248 in->ldap_msg = talloc(in, struct ldap_message);
249 if (in->ldap_msg == NULL) {
253 /* this initial decode is used to find the message id */
254 status = ldap_decode(asn1, NULL, in->ldap_msg);
255 if (!NT_STATUS_IS_OK(status)) {
259 /* find the pending request */
260 p = idr_find(c->searches.idr, in->ldap_msg->messageid);
262 if (!c->incoming.handler) {
266 /* this function should free or steal 'in' */
267 c->incoming.handler(c, c->incoming.private_data, in);
271 search = talloc_get_type(p, struct cldap_search_state);
272 search->response.in = talloc_move(search, &in);
273 search->response.asn1 = asn1;
274 search->response.asn1->ofs = 0;
276 DLIST_REMOVE(c->searches.list, search);
278 if (!cldap_recvfrom_setup(c)) {
282 tevent_req_done(search->req);
287 in->recv_errno = ENOMEM;
289 status = map_nt_error_from_unix_common(in->recv_errno);
291 /* in connected mode the first pending search gets the error */
293 /* otherwise we just ignore the error */
296 if (!c->searches.list) {
299 tevent_req_nterror(c->searches.list->req, status);
306 initialise a cldap_sock
308 NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx,
309 struct tevent_context *ev,
310 const struct tsocket_address *local_addr,
311 const struct tsocket_address *remote_addr,
312 struct cldap_socket **_cldap)
314 struct cldap_socket *c = NULL;
315 struct tsocket_address *any = NULL;
319 c = talloc_zero(mem_ctx, struct cldap_socket);
325 ev = tevent_context_init(c);
329 c->event.allow_poll = true;
334 /* we use ipv4 here instead of ip, as otherwise we end
335 up with a PF_INET6 socket, and sendto() for ipv4
336 addresses will fail. That breaks cldap name
337 resolution for winbind to IPv4 hosts. */
338 ret = tsocket_address_inet_from_strings(c, "ipv4",
342 status = map_nt_error_from_unix_common(errno);
348 c->searches.idr = idr_init(c);
349 if (!c->searches.idr) {
353 ret = tdgram_inet_udp_socket(local_addr, remote_addr,
356 status = map_nt_error_from_unix_common(errno);
365 c->send_queue = tevent_queue_create(c, "cldap_send_queue");
366 if (!c->send_queue) {
370 talloc_set_destructor(c, cldap_socket_destructor);
376 status = NT_STATUS_NO_MEMORY;
383 setup a handler for incoming requests
385 NTSTATUS cldap_set_incoming_handler(struct cldap_socket *c,
386 struct tevent_context *ev,
387 void (*handler)(struct cldap_socket *,
389 struct cldap_incoming *),
393 return NT_STATUS_PIPE_CONNECTED;
396 /* if sync requests are allowed, we don't allow an incoming handler */
397 if (c->event.allow_poll) {
398 return NT_STATUS_INVALID_PIPE_STATE;
401 c->incoming.handler = handler;
402 c->incoming.private_data = private_data;
404 if (!cldap_recvfrom_setup(c)) {
405 ZERO_STRUCT(c->incoming);
406 return NT_STATUS_NO_MEMORY;
412 struct cldap_reply_state {
413 struct tsocket_address *dest;
417 static void cldap_reply_state_destroy(struct tevent_req *subreq);
420 queue a cldap reply for send
422 NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
424 struct cldap_reply_state *state = NULL;
425 struct ldap_message *msg;
426 DATA_BLOB blob1, blob2;
428 struct tevent_req *subreq;
430 if (cldap->connected) {
431 return NT_STATUS_PIPE_CONNECTED;
435 return NT_STATUS_INVALID_ADDRESS;
438 state = talloc(cldap, struct cldap_reply_state);
439 NT_STATUS_HAVE_NO_MEMORY(state);
441 state->dest = tsocket_address_copy(io->dest, state);
446 msg = talloc(state, struct ldap_message);
451 msg->messageid = io->messageid;
452 msg->controls = NULL;
455 msg->type = LDAP_TAG_SearchResultEntry;
456 msg->r.SearchResultEntry = *io->response;
458 if (!ldap_encode(msg, NULL, &blob1, state)) {
459 status = NT_STATUS_INVALID_PARAMETER;
463 blob1 = data_blob(NULL, 0);
466 msg->type = LDAP_TAG_SearchResultDone;
467 msg->r.SearchResultDone = *io->result;
469 if (!ldap_encode(msg, NULL, &blob2, state)) {
470 status = NT_STATUS_INVALID_PARAMETER;
475 state->blob = data_blob_talloc(state, NULL, blob1.length + blob2.length);
476 if (!state->blob.data) {
480 memcpy(state->blob.data, blob1.data, blob1.length);
481 memcpy(state->blob.data+blob1.length, blob2.data, blob2.length);
482 data_blob_free(&blob1);
483 data_blob_free(&blob2);
485 subreq = tdgram_sendto_queue_send(state,
495 /* the callback will just free the state, as we don't need a result */
496 tevent_req_set_callback(subreq, cldap_reply_state_destroy, state);
501 status = NT_STATUS_NO_MEMORY;
507 static void cldap_reply_state_destroy(struct tevent_req *subreq)
509 struct cldap_reply_state *state = tevent_req_callback_data(subreq,
510 struct cldap_reply_state);
512 /* we don't want to know the result here, we just free the state */
517 static int cldap_search_state_destructor(struct cldap_search_state *s)
519 if (s->caller.cldap) {
520 if (s->message_id != -1) {
521 idr_remove(s->caller.cldap->searches.idr, s->message_id);
524 DLIST_REMOVE(s->caller.cldap->searches.list, s);
525 cldap_recvfrom_stop(s->caller.cldap);
526 ZERO_STRUCT(s->caller);
532 static void cldap_search_state_queue_done(struct tevent_req *subreq);
533 static void cldap_search_state_wakeup_done(struct tevent_req *subreq);
536 queue a cldap reply for send
538 struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
539 struct tevent_context *ev,
540 struct cldap_socket *cldap,
541 const struct cldap_search *io)
543 struct tevent_req *req, *subreq;
544 struct cldap_search_state *state = NULL;
545 struct ldap_message *msg;
546 struct ldap_SearchRequest *search;
552 req = tevent_req_create(mem_ctx, &state,
553 struct cldap_search_state);
558 state->caller.ev = ev;
560 state->caller.cldap = cldap;
561 state->message_id = -1;
563 talloc_set_destructor(state, cldap_search_state_destructor);
565 if (io->in.dest_address) {
566 if (cldap->connected) {
567 tevent_req_nterror(req, NT_STATUS_PIPE_CONNECTED);
570 ret = tsocket_address_inet_from_strings(state,
574 &state->request.dest);
576 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
580 if (!cldap->connected) {
581 tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
584 state->request.dest = NULL;
587 state->message_id = idr_get_new_random(cldap->searches.idr,
589 if (state->message_id == -1) {
590 tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
594 msg = talloc(state, struct ldap_message);
595 if (tevent_req_nomem(msg, req)) {
599 msg->messageid = state->message_id;
600 msg->type = LDAP_TAG_SearchRequest;
601 msg->controls = NULL;
602 search = &msg->r.SearchRequest;
605 search->scope = LDAP_SEARCH_SCOPE_BASE;
606 search->deref = LDAP_DEREFERENCE_NEVER;
607 search->timelimit = 0;
608 search->sizelimit = 0;
609 search->attributesonly = false;
610 search->num_attributes = str_list_length(io->in.attributes);
611 search->attributes = io->in.attributes;
612 search->tree = ldb_parse_tree(msg, io->in.filter);
613 if (tevent_req_nomem(search->tree, req)) {
617 if (!ldap_encode(msg, NULL, &state->request.blob, state)) {
618 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
623 state->request.idx = 0;
624 state->request.delay = 10*1000*1000;
625 state->request.count = 3;
626 if (io->in.timeout > 0) {
627 state->request.delay = io->in.timeout * 1000 * 1000;
628 state->request.count = io->in.retries + 1;
631 now = tevent_timeval_current();
633 for (i = 0; i < state->request.count; i++) {
634 end = tevent_timeval_add(&end, state->request.delay / 1000000,
635 state->request.delay % 1000000);
638 if (!tevent_req_set_endtime(req, state->caller.cldap->event.ctx, end)) {
643 subreq = tdgram_sendto_queue_send(state,
644 state->caller.cldap->event.ctx,
645 state->caller.cldap->sock,
646 state->caller.cldap->send_queue,
647 state->request.blob.data,
648 state->request.blob.length,
649 state->request.dest);
650 if (tevent_req_nomem(subreq, req)) {
653 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
655 DLIST_ADD_END(cldap->searches.list, state, struct cldap_search_state *);
660 return tevent_req_post(req, cldap->event.ctx);
663 static void cldap_search_state_queue_done(struct tevent_req *subreq)
665 struct tevent_req *req = tevent_req_callback_data(subreq,
667 struct cldap_search_state *state = tevent_req_data(req,
668 struct cldap_search_state);
673 ret = tdgram_sendto_queue_recv(subreq, &sys_errno);
677 status = map_nt_error_from_unix_common(sys_errno);
678 DLIST_REMOVE(state->caller.cldap->searches.list, state);
679 ZERO_STRUCT(state->caller.cldap);
680 tevent_req_nterror(req, status);
684 state->request.idx++;
686 /* wait for incoming traffic */
687 if (!cldap_recvfrom_setup(state->caller.cldap)) {
692 if (state->request.idx > state->request.count) {
693 /* we just wait for the response or a timeout */
697 next = tevent_timeval_current_ofs(state->request.delay / 1000000,
698 state->request.delay % 1000000);
699 subreq = tevent_wakeup_send(state,
700 state->caller.cldap->event.ctx,
702 if (tevent_req_nomem(subreq, req)) {
705 tevent_req_set_callback(subreq, cldap_search_state_wakeup_done, req);
708 static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
710 struct tevent_req *req = tevent_req_callback_data(subreq,
712 struct cldap_search_state *state = tevent_req_data(req,
713 struct cldap_search_state);
716 ok = tevent_wakeup_recv(subreq);
719 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
723 subreq = tdgram_sendto_queue_send(state,
724 state->caller.cldap->event.ctx,
725 state->caller.cldap->sock,
726 state->caller.cldap->send_queue,
727 state->request.blob.data,
728 state->request.blob.length,
729 state->request.dest);
730 if (tevent_req_nomem(subreq, req)) {
733 tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
737 receive a cldap reply
739 NTSTATUS cldap_search_recv(struct tevent_req *req,
741 struct cldap_search *io)
743 struct cldap_search_state *state = tevent_req_data(req,
744 struct cldap_search_state);
745 struct ldap_message *ldap_msg;
748 if (tevent_req_is_nterror(req, &status)) {
752 ldap_msg = talloc(mem_ctx, struct ldap_message);
757 status = ldap_decode(state->response.asn1, NULL, ldap_msg);
758 if (!NT_STATUS_IS_OK(status)) {
762 ZERO_STRUCT(io->out);
764 /* the first possible form has a search result in first place */
765 if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
766 io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
767 if (!io->out.response) {
770 *io->out.response = ldap_msg->r.SearchResultEntry;
772 /* decode the 2nd part */
773 status = ldap_decode(state->response.asn1, NULL, ldap_msg);
774 if (!NT_STATUS_IS_OK(status)) {
779 if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
780 status = NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
784 io->out.result = talloc(mem_ctx, struct ldap_Result);
785 if (!io->out.result) {
788 *io->out.result = ldap_msg->r.SearchResultDone;
790 if (io->out.result->resultcode != LDAP_SUCCESS) {
791 status = NT_STATUS_LDAP(io->out.result->resultcode);
795 tevent_req_received(req);
799 status = NT_STATUS_NO_MEMORY;
801 tevent_req_received(req);
807 synchronous cldap search
809 NTSTATUS cldap_search(struct cldap_socket *cldap,
811 struct cldap_search *io)
813 struct tevent_req *req;
816 if (!cldap->event.allow_poll) {
817 return NT_STATUS_INVALID_PIPE_STATE;
820 if (cldap->searches.list) {
821 return NT_STATUS_PIPE_BUSY;
824 req = cldap_search_send(mem_ctx, cldap->event.ctx, cldap, io);
825 NT_STATUS_HAVE_NO_MEMORY(req);
827 if (!tevent_req_poll(req, cldap->event.ctx)) {
829 return NT_STATUS_INTERNAL_ERROR;
832 status = cldap_search_recv(req, mem_ctx, io);
838 struct cldap_netlogon_state {
839 struct cldap_search search;
842 static void cldap_netlogon_state_done(struct tevent_req *subreq);
844 queue a cldap netlogon for send
846 struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
847 struct tevent_context *ev,
848 struct cldap_socket *cldap,
849 const struct cldap_netlogon *io)
851 struct tevent_req *req, *subreq;
852 struct cldap_netlogon_state *state;
854 static const char * const attr[] = { "NetLogon", NULL };
856 req = tevent_req_create(mem_ctx, &state,
857 struct cldap_netlogon_state);
862 filter = talloc_asprintf(state, "(&(NtVer=%s)",
863 ldap_encode_ndr_uint32(state, io->in.version));
864 if (tevent_req_nomem(filter, req)) {
868 filter = talloc_asprintf_append_buffer(filter, "(User=%s)", io->in.user);
869 if (tevent_req_nomem(filter, req)) {
874 filter = talloc_asprintf_append_buffer(filter, "(Host=%s)", io->in.host);
875 if (tevent_req_nomem(filter, req)) {
880 filter = talloc_asprintf_append_buffer(filter, "(DnsDomain=%s)", io->in.realm);
881 if (tevent_req_nomem(filter, req)) {
885 if (io->in.acct_control != -1) {
886 filter = talloc_asprintf_append_buffer(filter, "(AAC=%s)",
887 ldap_encode_ndr_uint32(state, io->in.acct_control));
888 if (tevent_req_nomem(filter, req)) {
892 if (io->in.domain_sid) {
893 struct dom_sid *sid = dom_sid_parse_talloc(state, io->in.domain_sid);
894 if (tevent_req_nomem(sid, req)) {
897 filter = talloc_asprintf_append_buffer(filter, "(domainSid=%s)",
898 ldap_encode_ndr_dom_sid(state, sid));
899 if (tevent_req_nomem(filter, req)) {
903 if (io->in.domain_guid) {
906 status = GUID_from_string(io->in.domain_guid, &guid);
907 if (tevent_req_nterror(req, status)) {
910 filter = talloc_asprintf_append_buffer(filter, "(DomainGuid=%s)",
911 ldap_encode_ndr_GUID(state, &guid));
912 if (tevent_req_nomem(filter, req)) {
916 filter = talloc_asprintf_append_buffer(filter, ")");
917 if (tevent_req_nomem(filter, req)) {
921 if (io->in.dest_address) {
922 state->search.in.dest_address = talloc_strdup(state,
923 io->in.dest_address);
924 if (tevent_req_nomem(state->search.in.dest_address, req)) {
927 state->search.in.dest_port = io->in.dest_port;
929 state->search.in.dest_address = NULL;
930 state->search.in.dest_port = 0;
932 state->search.in.filter = filter;
933 state->search.in.attributes = attr;
934 state->search.in.timeout = 2;
935 state->search.in.retries = 2;
937 subreq = cldap_search_send(state, ev, cldap, &state->search);
938 if (tevent_req_nomem(subreq, req)) {
941 tevent_req_set_callback(subreq, cldap_netlogon_state_done, req);
945 return tevent_req_post(req, cldap->event.ctx);
948 static void cldap_netlogon_state_done(struct tevent_req *subreq)
950 struct tevent_req *req = tevent_req_callback_data(subreq,
952 struct cldap_netlogon_state *state = tevent_req_data(req,
953 struct cldap_netlogon_state);
956 status = cldap_search_recv(subreq, state, &state->search);
959 if (tevent_req_nterror(req, status)) {
963 tevent_req_done(req);
967 receive a cldap netlogon reply
969 NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
971 struct cldap_netlogon *io)
973 struct cldap_netlogon_state *state = tevent_req_data(req,
974 struct cldap_netlogon_state);
978 if (tevent_req_is_nterror(req, &status)) {
982 if (state->search.out.response == NULL) {
983 status = NT_STATUS_NOT_FOUND;
987 if (state->search.out.response->num_attributes != 1 ||
988 strcasecmp(state->search.out.response->attributes[0].name, "netlogon") != 0 ||
989 state->search.out.response->attributes[0].num_values != 1 ||
990 state->search.out.response->attributes[0].values->length < 2) {
991 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
994 data = state->search.out.response->attributes[0].values;
996 status = pull_netlogon_samlogon_response(data, mem_ctx,
998 if (!NT_STATUS_IS_OK(status)) {
1002 if (io->in.map_response) {
1003 map_netlogon_samlogon_response(&io->out.netlogon);
1006 status = NT_STATUS_OK;
1008 tevent_req_received(req);
1013 sync cldap netlogon search
1015 NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
1016 TALLOC_CTX *mem_ctx,
1017 struct cldap_netlogon *io)
1019 struct tevent_req *req;
1022 if (!cldap->event.allow_poll) {
1023 return NT_STATUS_INVALID_PIPE_STATE;
1026 if (cldap->searches.list) {
1027 return NT_STATUS_PIPE_BUSY;
1030 req = cldap_netlogon_send(mem_ctx, cldap->event.ctx, cldap, io);
1031 NT_STATUS_HAVE_NO_MEMORY(req);
1033 if (!tevent_req_poll(req, cldap->event.ctx)) {
1035 return NT_STATUS_INTERNAL_ERROR;
1038 status = cldap_netlogon_recv(req, mem_ctx, io);
1046 send an empty reply (used on any error, so the client doesn't keep waiting
1047 or send the bad request again)
1049 NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
1050 uint32_t message_id,
1051 struct tsocket_address *dest)
1054 struct cldap_reply reply;
1055 struct ldap_Result result;
1057 reply.messageid = message_id;
1059 reply.response = NULL;
1060 reply.result = &result;
1062 ZERO_STRUCT(result);
1064 status = cldap_reply_send(cldap, &reply);
1070 send an error reply (used on any error, so the client doesn't keep waiting
1071 or send the bad request again)
1073 NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
1074 uint32_t message_id,
1075 struct tsocket_address *dest,
1077 const char *errormessage)
1080 struct cldap_reply reply;
1081 struct ldap_Result result;
1083 reply.messageid = message_id;
1085 reply.response = NULL;
1086 reply.result = &result;
1088 ZERO_STRUCT(result);
1089 result.resultcode = resultcode;
1090 result.errormessage = errormessage;
1092 status = cldap_reply_send(cldap, &reply);
1099 send a netlogon reply
1101 NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
1102 uint32_t message_id,
1103 struct tsocket_address *dest,
1105 struct netlogon_samlogon_response *netlogon)
1108 struct cldap_reply reply;
1109 struct ldap_SearchResEntry response;
1110 struct ldap_Result result;
1111 TALLOC_CTX *tmp_ctx = talloc_new(cldap);
1114 status = push_netlogon_samlogon_response(&blob, tmp_ctx,
1116 if (!NT_STATUS_IS_OK(status)) {
1117 talloc_free(tmp_ctx);
1120 reply.messageid = message_id;
1122 reply.response = &response;
1123 reply.result = &result;
1125 ZERO_STRUCT(result);
1128 response.num_attributes = 1;
1129 response.attributes = talloc(tmp_ctx, struct ldb_message_element);
1130 NT_STATUS_HAVE_NO_MEMORY(response.attributes);
1131 response.attributes->name = "netlogon";
1132 response.attributes->num_values = 1;
1133 response.attributes->values = &blob;
1135 status = cldap_reply_send(cldap, &reply);
1137 talloc_free(tmp_ctx);