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 void 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
;
180 c
->recv_subreq
= NULL
;
182 in
= talloc_zero(c
, struct cldap_incoming
);
187 ret
= tdgram_recvfrom_recv(subreq
,
197 if (ret
== -1 && in
->recv_errno
== 0) {
198 in
->recv_errno
= EIO
;
201 /* this function should free or steal 'in' */
202 cldap_socket_recv_dgram(c
, in
);
205 if (!cldap_recvfrom_setup(c
)) {
214 /*TODO: call a dead socket handler */
219 handle recv events on a cldap socket
221 static void cldap_socket_recv_dgram(struct cldap_socket
*c
,
222 struct cldap_incoming
*in
)
225 struct asn1_data
*asn1
;
227 struct cldap_search_state
*search
;
230 if (in
->recv_errno
!= 0) {
234 blob
= data_blob_const(in
->buf
, in
->len
);
236 asn1
= asn1_init(in
);
241 if (!asn1_load(asn1
, blob
)) {
245 in
->ldap_msg
= talloc(in
, struct ldap_message
);
246 if (in
->ldap_msg
== NULL
) {
250 /* this initial decode is used to find the message id */
251 status
= ldap_decode(asn1
, NULL
, in
->ldap_msg
);
252 if (!NT_STATUS_IS_OK(status
)) {
256 /* find the pending request */
257 p
= idr_find(c
->searches
.idr
, in
->ldap_msg
->messageid
);
259 if (!c
->incoming
.handler
) {
263 /* this function should free or steal 'in' */
264 c
->incoming
.handler(c
, c
->incoming
.private_data
, in
);
268 search
= talloc_get_type(p
, struct cldap_search_state
);
269 search
->response
.in
= talloc_move(search
, &in
);
270 search
->response
.asn1
= asn1
;
271 search
->response
.asn1
->ofs
= 0;
273 tevent_req_done(search
->req
);
277 in
->recv_errno
= ENOMEM
;
279 status
= map_nt_error_from_unix(in
->recv_errno
);
281 /* in connected mode the first pending search gets the error */
283 /* otherwise we just ignore the error */
286 if (!c
->searches
.list
) {
289 tevent_req_nterror(c
->searches
.list
->req
, status
);
295 initialise a cldap_sock
297 NTSTATUS
cldap_socket_init(TALLOC_CTX
*mem_ctx
,
298 struct tevent_context
*ev
,
299 const struct tsocket_address
*local_addr
,
300 const struct tsocket_address
*remote_addr
,
301 struct cldap_socket
**_cldap
)
303 struct cldap_socket
*c
= NULL
;
304 struct tsocket_address
*any
= NULL
;
308 c
= talloc_zero(mem_ctx
, struct cldap_socket
);
314 ev
= tevent_context_init(c
);
318 c
->event
.allow_poll
= true;
323 ret
= tsocket_address_inet_from_strings(c
, "ipv4",
327 status
= map_nt_error_from_unix(errno
);
333 c
->searches
.idr
= idr_init(c
);
334 if (!c
->searches
.idr
) {
338 ret
= tdgram_inet_udp_socket(local_addr
, remote_addr
,
341 status
= map_nt_error_from_unix(errno
);
350 c
->send_queue
= tevent_queue_create(c
, "cldap_send_queue");
351 if (!c
->send_queue
) {
355 talloc_set_destructor(c
, cldap_socket_destructor
);
361 status
= NT_STATUS_NO_MEMORY
;
368 setup a handler for incoming requests
370 NTSTATUS
cldap_set_incoming_handler(struct cldap_socket
*c
,
371 void (*handler
)(struct cldap_socket
*,
373 struct cldap_incoming
*),
377 return NT_STATUS_PIPE_CONNECTED
;
380 /* if sync requests are allowed, we don't allow an incoming handler */
381 if (c
->event
.allow_poll
) {
382 return NT_STATUS_INVALID_PIPE_STATE
;
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
;
419 return NT_STATUS_INVALID_ADDRESS
;
422 state
= talloc(cldap
, struct cldap_reply_state
);
423 NT_STATUS_HAVE_NO_MEMORY(state
);
425 state
->dest
= tsocket_address_copy(io
->dest
, state
);
430 msg
= talloc(state
, struct ldap_message
);
435 msg
->messageid
= io
->messageid
;
436 msg
->controls
= NULL
;
439 msg
->type
= LDAP_TAG_SearchResultEntry
;
440 msg
->r
.SearchResultEntry
= *io
->response
;
442 if (!ldap_encode(msg
, NULL
, &blob1
, state
)) {
443 status
= NT_STATUS_INVALID_PARAMETER
;
447 blob1
= data_blob(NULL
, 0);
450 msg
->type
= LDAP_TAG_SearchResultDone
;
451 msg
->r
.SearchResultDone
= *io
->result
;
453 if (!ldap_encode(msg
, NULL
, &blob2
, state
)) {
454 status
= NT_STATUS_INVALID_PARAMETER
;
459 state
->blob
= data_blob_talloc(state
, NULL
, blob1
.length
+ blob2
.length
);
460 if (!state
->blob
.data
) {
464 memcpy(state
->blob
.data
, blob1
.data
, blob1
.length
);
465 memcpy(state
->blob
.data
+blob1
.length
, blob2
.data
, blob2
.length
);
466 data_blob_free(&blob1
);
467 data_blob_free(&blob2
);
469 subreq
= tdgram_sendto_queue_send(state
,
479 /* the callback will just free the state, as we don't need a result */
480 tevent_req_set_callback(subreq
, cldap_reply_state_destroy
, state
);
485 status
= NT_STATUS_NO_MEMORY
;
491 static void cldap_reply_state_destroy(struct tevent_req
*subreq
)
493 struct cldap_reply_state
*state
= tevent_req_callback_data(subreq
,
494 struct cldap_reply_state
);
496 /* we don't want to know the result here, we just free the state */
501 static int cldap_search_state_destructor(struct cldap_search_state
*s
)
503 if (s
->caller
.cldap
) {
504 if (s
->message_id
!= -1) {
505 idr_remove(s
->caller
.cldap
->searches
.idr
, s
->message_id
);
508 DLIST_REMOVE(s
->caller
.cldap
->searches
.list
, s
);
509 cldap_recvfrom_stop(s
->caller
.cldap
);
510 ZERO_STRUCT(s
->caller
);
516 static void cldap_search_state_queue_done(struct tevent_req
*subreq
);
517 static void cldap_search_state_wakeup_done(struct tevent_req
*subreq
);
520 queue a cldap reply for send
522 struct tevent_req
*cldap_search_send(TALLOC_CTX
*mem_ctx
,
523 struct cldap_socket
*cldap
,
524 const struct cldap_search
*io
)
526 struct tevent_req
*req
, *subreq
;
527 struct cldap_search_state
*state
= NULL
;
528 struct ldap_message
*msg
;
529 struct ldap_SearchRequest
*search
;
535 req
= tevent_req_create(mem_ctx
, &state
,
536 struct cldap_search_state
);
542 state
->caller
.cldap
= cldap
;
543 state
->message_id
= -1;
545 talloc_set_destructor(state
, cldap_search_state_destructor
);
547 if (io
->in
.dest_address
) {
548 if (cldap
->connected
) {
549 tevent_req_nterror(req
, NT_STATUS_PIPE_CONNECTED
);
552 ret
= tsocket_address_inet_from_strings(state
,
556 &state
->request
.dest
);
558 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
562 if (!cldap
->connected
) {
563 tevent_req_nterror(req
, NT_STATUS_INVALID_ADDRESS
);
566 state
->request
.dest
= NULL
;
569 state
->message_id
= idr_get_new_random(cldap
->searches
.idr
,
571 if (state
->message_id
== -1) {
572 tevent_req_nterror(req
, NT_STATUS_INSUFFICIENT_RESOURCES
);
576 msg
= talloc(state
, struct ldap_message
);
577 if (tevent_req_nomem(msg
, req
)) {
581 msg
->messageid
= state
->message_id
;
582 msg
->type
= LDAP_TAG_SearchRequest
;
583 msg
->controls
= NULL
;
584 search
= &msg
->r
.SearchRequest
;
587 search
->scope
= LDAP_SEARCH_SCOPE_BASE
;
588 search
->deref
= LDAP_DEREFERENCE_NEVER
;
589 search
->timelimit
= 0;
590 search
->sizelimit
= 0;
591 search
->attributesonly
= false;
592 search
->num_attributes
= str_list_length(io
->in
.attributes
);
593 search
->attributes
= io
->in
.attributes
;
594 search
->tree
= ldb_parse_tree(msg
, io
->in
.filter
);
595 if (tevent_req_nomem(search
->tree
, req
)) {
599 if (!ldap_encode(msg
, NULL
, &state
->request
.blob
, state
)) {
600 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
605 state
->request
.idx
= 0;
606 state
->request
.delay
= 10*1000*1000;
607 state
->request
.count
= 3;
608 if (io
->in
.timeout
> 0) {
609 state
->request
.delay
= io
->in
.timeout
* 1000 * 1000;
610 state
->request
.count
= io
->in
.retries
+ 1;
613 now
= tevent_timeval_current();
615 for (i
= 0; i
< state
->request
.count
; i
++) {
616 end
= tevent_timeval_add(&end
, 0, state
->request
.delay
);
619 if (!tevent_req_set_endtime(req
, state
->caller
.cldap
->event
.ctx
, end
)) {
620 tevent_req_nomem(NULL
, req
);
624 subreq
= tdgram_sendto_queue_send(state
,
625 state
->caller
.cldap
->event
.ctx
,
626 state
->caller
.cldap
->sock
,
627 state
->caller
.cldap
->send_queue
,
628 state
->request
.blob
.data
,
629 state
->request
.blob
.length
,
630 state
->request
.dest
);
631 if (tevent_req_nomem(subreq
, req
)) {
634 tevent_req_set_callback(subreq
, cldap_search_state_queue_done
, req
);
636 DLIST_ADD_END(cldap
->searches
.list
, state
, struct cldap_search_state
*);
641 return tevent_req_post(req
, cldap
->event
.ctx
);
644 static void cldap_search_state_queue_done(struct tevent_req
*subreq
)
646 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
648 struct cldap_search_state
*state
= tevent_req_data(req
,
649 struct cldap_search_state
);
654 ret
= tdgram_sendto_queue_recv(subreq
, &sys_errno
);
658 status
= map_nt_error_from_unix(sys_errno
);
659 DLIST_REMOVE(state
->caller
.cldap
->searches
.list
, state
);
660 ZERO_STRUCT(state
->caller
.cldap
);
661 tevent_req_nterror(req
, status
);
665 state
->request
.idx
++;
667 /* wait for incoming traffic */
668 if (!cldap_recvfrom_setup(state
->caller
.cldap
)) {
669 tevent_req_nomem(NULL
, req
);
673 if (state
->request
.idx
> state
->request
.count
) {
674 /* we just wait for the response or a timeout */
678 next
= tevent_timeval_current_ofs(0, state
->request
.delay
);
679 subreq
= tevent_wakeup_send(state
,
680 state
->caller
.cldap
->event
.ctx
,
682 if (tevent_req_nomem(subreq
, req
)) {
685 tevent_req_set_callback(subreq
, cldap_search_state_wakeup_done
, req
);
688 static void cldap_search_state_wakeup_done(struct tevent_req
*subreq
)
690 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
692 struct cldap_search_state
*state
= tevent_req_data(req
,
693 struct cldap_search_state
);
696 ok
= tevent_wakeup_recv(subreq
);
699 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
703 subreq
= tdgram_sendto_queue_send(state
,
704 state
->caller
.cldap
->event
.ctx
,
705 state
->caller
.cldap
->sock
,
706 state
->caller
.cldap
->send_queue
,
707 state
->request
.blob
.data
,
708 state
->request
.blob
.length
,
709 state
->request
.dest
);
710 if (tevent_req_nomem(subreq
, req
)) {
713 tevent_req_set_callback(subreq
, cldap_search_state_queue_done
, req
);
717 receive a cldap reply
719 NTSTATUS
cldap_search_recv(struct tevent_req
*req
,
721 struct cldap_search
*io
)
723 struct cldap_search_state
*state
= tevent_req_data(req
,
724 struct cldap_search_state
);
725 struct ldap_message
*ldap_msg
;
728 if (tevent_req_is_nterror(req
, &status
)) {
732 ldap_msg
= talloc(mem_ctx
, struct ldap_message
);
737 status
= ldap_decode(state
->response
.asn1
, NULL
, ldap_msg
);
738 if (!NT_STATUS_IS_OK(status
)) {
742 ZERO_STRUCT(io
->out
);
744 /* the first possible form has a search result in first place */
745 if (ldap_msg
->type
== LDAP_TAG_SearchResultEntry
) {
746 io
->out
.response
= talloc(mem_ctx
, struct ldap_SearchResEntry
);
747 if (!io
->out
.response
) {
750 *io
->out
.response
= ldap_msg
->r
.SearchResultEntry
;
752 /* decode the 2nd part */
753 status
= ldap_decode(state
->response
.asn1
, NULL
, ldap_msg
);
754 if (!NT_STATUS_IS_OK(status
)) {
759 if (ldap_msg
->type
!= LDAP_TAG_SearchResultDone
) {
760 status
= NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR
);
764 io
->out
.result
= talloc(mem_ctx
, struct ldap_Result
);
765 if (!io
->out
.result
) {
768 *io
->out
.result
= ldap_msg
->r
.SearchResultDone
;
770 if (io
->out
.result
->resultcode
!= LDAP_SUCCESS
) {
771 status
= NT_STATUS_LDAP(io
->out
.result
->resultcode
);
775 tevent_req_received(req
);
779 status
= NT_STATUS_NO_MEMORY
;
781 tevent_req_received(req
);
787 synchronous cldap search
789 NTSTATUS
cldap_search(struct cldap_socket
*cldap
,
791 struct cldap_search
*io
)
793 struct tevent_req
*req
;
796 if (!cldap
->event
.allow_poll
) {
797 return NT_STATUS_INVALID_PIPE_STATE
;
800 if (cldap
->searches
.list
) {
801 return NT_STATUS_PIPE_BUSY
;
804 req
= cldap_search_send(mem_ctx
, cldap
, io
);
805 NT_STATUS_HAVE_NO_MEMORY(req
);
807 if (!tevent_req_poll(req
, cldap
->event
.ctx
)) {
809 return NT_STATUS_INTERNAL_ERROR
;
812 status
= cldap_search_recv(req
, mem_ctx
, io
);
818 struct cldap_netlogon_state
{
819 struct cldap_search search
;
822 static void cldap_netlogon_state_done(struct tevent_req
*subreq
);
824 queue a cldap netlogon for send
826 struct tevent_req
*cldap_netlogon_send(TALLOC_CTX
*mem_ctx
,
827 struct cldap_socket
*cldap
,
828 const struct cldap_netlogon
*io
)
830 struct tevent_req
*req
, *subreq
;
831 struct cldap_netlogon_state
*state
;
833 static const char * const attr
[] = { "NetLogon", NULL
};
835 req
= tevent_req_create(mem_ctx
, &state
,
836 struct cldap_netlogon_state
);
841 filter
= talloc_asprintf(state
, "(&(NtVer=%s)",
842 ldap_encode_ndr_uint32(state
, io
->in
.version
));
843 if (tevent_req_nomem(filter
, req
)) {
847 filter
= talloc_asprintf_append_buffer(filter
, "(User=%s)", io
->in
.user
);
848 if (tevent_req_nomem(filter
, req
)) {
853 filter
= talloc_asprintf_append_buffer(filter
, "(Host=%s)", io
->in
.host
);
854 if (tevent_req_nomem(filter
, req
)) {
859 filter
= talloc_asprintf_append_buffer(filter
, "(DnsDomain=%s)", io
->in
.realm
);
860 if (tevent_req_nomem(filter
, req
)) {
864 if (io
->in
.acct_control
!= -1) {
865 filter
= talloc_asprintf_append_buffer(filter
, "(AAC=%s)",
866 ldap_encode_ndr_uint32(state
, io
->in
.acct_control
));
867 if (tevent_req_nomem(filter
, req
)) {
871 if (io
->in
.domain_sid
) {
872 struct dom_sid
*sid
= dom_sid_parse_talloc(state
, io
->in
.domain_sid
);
873 if (tevent_req_nomem(sid
, req
)) {
876 filter
= talloc_asprintf_append_buffer(filter
, "(domainSid=%s)",
877 ldap_encode_ndr_dom_sid(state
, sid
));
878 if (tevent_req_nomem(filter
, req
)) {
882 if (io
->in
.domain_guid
) {
885 status
= GUID_from_string(io
->in
.domain_guid
, &guid
);
886 if (tevent_req_nterror(req
, status
)) {
889 filter
= talloc_asprintf_append_buffer(filter
, "(DomainGuid=%s)",
890 ldap_encode_ndr_GUID(state
, &guid
));
891 if (tevent_req_nomem(filter
, req
)) {
895 filter
= talloc_asprintf_append_buffer(filter
, ")");
896 if (tevent_req_nomem(filter
, req
)) {
900 if (io
->in
.dest_address
) {
901 state
->search
.in
.dest_address
= talloc_strdup(state
,
902 io
->in
.dest_address
);
903 if (tevent_req_nomem(state
->search
.in
.dest_address
, req
)) {
906 state
->search
.in
.dest_port
= io
->in
.dest_port
;
908 state
->search
.in
.dest_address
= NULL
;
909 state
->search
.in
.dest_port
= 0;
911 state
->search
.in
.filter
= filter
;
912 state
->search
.in
.attributes
= attr
;
913 state
->search
.in
.timeout
= 2;
914 state
->search
.in
.retries
= 2;
916 subreq
= cldap_search_send(state
, cldap
, &state
->search
);
917 if (tevent_req_nomem(subreq
, req
)) {
920 tevent_req_set_callback(subreq
, cldap_netlogon_state_done
, req
);
924 return tevent_req_post(req
, cldap
->event
.ctx
);
927 static void cldap_netlogon_state_done(struct tevent_req
*subreq
)
929 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
931 struct cldap_netlogon_state
*state
= tevent_req_data(req
,
932 struct cldap_netlogon_state
);
935 status
= cldap_search_recv(subreq
, state
, &state
->search
);
938 if (tevent_req_nterror(req
, status
)) {
942 tevent_req_done(req
);
946 receive a cldap netlogon reply
948 NTSTATUS
cldap_netlogon_recv(struct tevent_req
*req
,
949 struct smb_iconv_convenience
*iconv_convenience
,
951 struct cldap_netlogon
*io
)
953 struct cldap_netlogon_state
*state
= tevent_req_data(req
,
954 struct cldap_netlogon_state
);
958 if (tevent_req_is_nterror(req
, &status
)) {
962 if (state
->search
.out
.response
== NULL
) {
963 status
= NT_STATUS_NOT_FOUND
;
967 if (state
->search
.out
.response
->num_attributes
!= 1 ||
968 strcasecmp(state
->search
.out
.response
->attributes
[0].name
, "netlogon") != 0 ||
969 state
->search
.out
.response
->attributes
[0].num_values
!= 1 ||
970 state
->search
.out
.response
->attributes
[0].values
->length
< 2) {
971 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
974 data
= state
->search
.out
.response
->attributes
[0].values
;
976 status
= pull_netlogon_samlogon_response(data
, mem_ctx
,
979 if (!NT_STATUS_IS_OK(status
)) {
983 if (io
->in
.map_response
) {
984 map_netlogon_samlogon_response(&io
->out
.netlogon
);
987 status
= NT_STATUS_OK
;
989 tevent_req_received(req
);
994 sync cldap netlogon search
996 NTSTATUS
cldap_netlogon(struct cldap_socket
*cldap
,
997 struct smb_iconv_convenience
*iconv_convenience
,
999 struct cldap_netlogon
*io
)
1001 struct tevent_req
*req
;
1004 if (!cldap
->event
.allow_poll
) {
1005 return NT_STATUS_INVALID_PIPE_STATE
;
1008 if (cldap
->searches
.list
) {
1009 return NT_STATUS_PIPE_BUSY
;
1012 req
= cldap_netlogon_send(mem_ctx
, cldap
, io
);
1013 NT_STATUS_HAVE_NO_MEMORY(req
);
1015 if (!tevent_req_poll(req
, cldap
->event
.ctx
)) {
1017 return NT_STATUS_INTERNAL_ERROR
;
1020 status
= cldap_netlogon_recv(req
, iconv_convenience
, mem_ctx
, io
);
1028 send an empty reply (used on any error, so the client doesn't keep waiting
1029 or send the bad request again)
1031 NTSTATUS
cldap_empty_reply(struct cldap_socket
*cldap
,
1032 uint32_t message_id
,
1033 struct tsocket_address
*dest
)
1036 struct cldap_reply reply
;
1037 struct ldap_Result result
;
1039 reply
.messageid
= message_id
;
1041 reply
.response
= NULL
;
1042 reply
.result
= &result
;
1044 ZERO_STRUCT(result
);
1046 status
= cldap_reply_send(cldap
, &reply
);
1052 send an error reply (used on any error, so the client doesn't keep waiting
1053 or send the bad request again)
1055 NTSTATUS
cldap_error_reply(struct cldap_socket
*cldap
,
1056 uint32_t message_id
,
1057 struct tsocket_address
*dest
,
1059 const char *errormessage
)
1062 struct cldap_reply reply
;
1063 struct ldap_Result result
;
1065 reply
.messageid
= message_id
;
1067 reply
.response
= NULL
;
1068 reply
.result
= &result
;
1070 ZERO_STRUCT(result
);
1071 result
.resultcode
= resultcode
;
1072 result
.errormessage
= errormessage
;
1074 status
= cldap_reply_send(cldap
, &reply
);
1081 send a netlogon reply
1083 NTSTATUS
cldap_netlogon_reply(struct cldap_socket
*cldap
,
1084 struct smb_iconv_convenience
*iconv_convenience
,
1085 uint32_t message_id
,
1086 struct tsocket_address
*dest
,
1088 struct netlogon_samlogon_response
*netlogon
)
1091 struct cldap_reply reply
;
1092 struct ldap_SearchResEntry response
;
1093 struct ldap_Result result
;
1094 TALLOC_CTX
*tmp_ctx
= talloc_new(cldap
);
1097 status
= push_netlogon_samlogon_response(&blob
, tmp_ctx
,
1100 if (!NT_STATUS_IS_OK(status
)) {
1101 talloc_free(tmp_ctx
);
1104 reply
.messageid
= message_id
;
1106 reply
.response
= &response
;
1107 reply
.result
= &result
;
1109 ZERO_STRUCT(result
);
1112 response
.num_attributes
= 1;
1113 response
.attributes
= talloc(tmp_ctx
, struct ldb_message_element
);
1114 NT_STATUS_HAVE_NO_MEMORY(response
.attributes
);
1115 response
.attributes
->name
= "netlogon";
1116 response
.attributes
->num_values
= 1;
1117 response
.attributes
->values
= &blob
;
1119 status
= cldap_reply_send(cldap
, &reply
);
1121 talloc_free(tmp_ctx
);