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"
46 #include "lib/util/idtree_random.h"
51 context structure for operations on cldap packets
54 /* the low level socket */
55 struct tdgram_context
*sock
;
58 * Are we in connected mode, which means
59 * we get ICMP errors back instead of timing
60 * out requests. And we can only send requests
61 * to the connected peer.
65 /* the queue for outgoing dgrams */
66 struct tevent_queue
*send_queue
;
68 /* do we have an async tsocket_recvfrom request pending */
69 struct tevent_req
*recv_subreq
;
72 /* a queue of pending search requests */
73 struct cldap_search_state
*list
;
75 /* mapping from message_id to pending request */
76 struct idr_context
*idr
;
79 /* what to do with incoming request packets */
81 struct tevent_context
*ev
;
82 void (*handler
)(struct cldap_socket
*,
84 struct cldap_incoming
*);
89 struct cldap_search_state
{
90 struct cldap_search_state
*prev
, *next
;
93 struct tevent_context
*ev
;
94 struct cldap_socket
*cldap
;
103 struct tsocket_address
*dest
;
108 struct cldap_incoming
*in
;
109 struct asn1_data
*asn1
;
112 struct tevent_req
*req
;
116 * For CLDAP we limit the maximum search request size to 4kb
118 #define MAX_SEARCH_REQUEST 4096
120 static int cldap_socket_destructor(struct cldap_socket
*c
)
122 while (c
->searches
.list
) {
123 struct cldap_search_state
*s
= c
->searches
.list
;
124 DLIST_REMOVE(c
->searches
.list
, s
);
125 ZERO_STRUCT(s
->caller
);
128 talloc_free(c
->recv_subreq
);
129 talloc_free(c
->send_queue
);
130 talloc_free(c
->sock
);
134 static void cldap_recvfrom_done(struct tevent_req
*subreq
);
136 static bool cldap_recvfrom_setup(struct cldap_socket
*c
)
138 struct tevent_context
*ev
;
140 if (c
->recv_subreq
) {
144 if (!c
->searches
.list
&& !c
->incoming
.handler
) {
150 /* this shouldn't happen but should be protected against */
151 if (c
->searches
.list
== NULL
) {
154 ev
= c
->searches
.list
->caller
.ev
;
157 c
->recv_subreq
= tdgram_recvfrom_send(c
, ev
, c
->sock
);
158 if (!c
->recv_subreq
) {
161 tevent_req_set_callback(c
->recv_subreq
, cldap_recvfrom_done
, c
);
166 static void cldap_recvfrom_stop(struct cldap_socket
*c
)
168 if (!c
->recv_subreq
) {
172 if (c
->searches
.list
|| c
->incoming
.handler
) {
176 talloc_free(c
->recv_subreq
);
177 c
->recv_subreq
= NULL
;
180 static bool cldap_socket_recv_dgram(struct cldap_socket
*c
,
181 struct cldap_incoming
*in
);
183 static void cldap_recvfrom_done(struct tevent_req
*subreq
)
185 struct cldap_socket
*c
= tevent_req_callback_data(subreq
,
186 struct cldap_socket
);
187 struct cldap_incoming
*in
= NULL
;
191 c
->recv_subreq
= NULL
;
193 in
= talloc_zero(c
, struct cldap_incoming
);
198 ret
= tdgram_recvfrom_recv(subreq
,
208 if (ret
== -1 && in
->recv_errno
== 0) {
209 in
->recv_errno
= EIO
;
212 /* this function should free or steal 'in' */
213 setup_done
= cldap_socket_recv_dgram(c
, in
);
216 if (!setup_done
&& !cldap_recvfrom_setup(c
)) {
228 handle recv events on a cldap socket
230 static bool cldap_socket_recv_dgram(struct cldap_socket
*c
,
231 struct cldap_incoming
*in
)
233 struct asn1_data
*asn1
;
235 struct cldap_search_state
*search
;
237 struct ldap_request_limits limits
= {
238 .max_search_size
= MAX_SEARCH_REQUEST
241 if (in
->recv_errno
!= 0) {
245 asn1
= asn1_init(in
, ASN1_MAX_TREE_DEPTH
);
250 asn1_load_nocopy(asn1
, in
->buf
, in
->len
);
252 in
->ldap_msg
= talloc(in
, struct ldap_message
);
253 if (in
->ldap_msg
== NULL
) {
257 /* this initial decode is used to find the message id */
258 status
= ldap_decode(asn1
, &limits
, NULL
, in
->ldap_msg
);
259 if (!NT_STATUS_IS_OK(status
)) {
263 /* find the pending request */
264 p
= idr_find(c
->searches
.idr
, in
->ldap_msg
->messageid
);
266 if (!c
->incoming
.handler
) {
271 /* this function should free or steal 'in' */
272 c
->incoming
.handler(c
, c
->incoming
.private_data
, in
);
276 search
= talloc_get_type_abort(p
, struct cldap_search_state
);
277 search
->response
.in
= talloc_move(search
, &in
);
279 search
->response
.asn1
= asn1
;
281 asn1_load_nocopy(search
->response
.asn1
,
282 search
->response
.in
->buf
, search
->response
.in
->len
);
284 DLIST_REMOVE(c
->searches
.list
, search
);
286 if (cldap_recvfrom_setup(c
)) {
287 tevent_req_done(search
->req
);
292 * This request was ok, just defer the notify of the caller
293 * and then just fail the next request if needed
295 tevent_req_defer_callback(search
->req
, search
->caller
.ev
);
296 tevent_req_done(search
->req
);
298 status
= NT_STATUS_NO_MEMORY
;
299 /* in is NULL it this point */
302 in
->recv_errno
= ENOMEM
;
304 status
= map_nt_error_from_unix_common(in
->recv_errno
);
307 /* in connected mode the first pending search gets the error */
309 /* otherwise we just ignore the error */
312 if (!c
->searches
.list
) {
316 * We might called tevent_req_done() for a successful
317 * search before, so we better deliver the failure
318 * after the success, that is why we better also
319 * use tevent_req_defer_callback() here.
321 tevent_req_defer_callback(c
->searches
.list
->req
,
322 c
->searches
.list
->caller
.ev
);
323 tevent_req_nterror(c
->searches
.list
->req
, status
);
328 initialise a cldap_sock
330 NTSTATUS
cldap_socket_init(TALLOC_CTX
*mem_ctx
,
331 const struct tsocket_address
*local_addr
,
332 const struct tsocket_address
*remote_addr
,
333 struct cldap_socket
**_cldap
)
335 struct cldap_socket
*c
= NULL
;
336 struct tsocket_address
*any
= NULL
;
339 const char *fam
= NULL
;
341 if (local_addr
== NULL
&& remote_addr
== NULL
) {
342 return NT_STATUS_INVALID_PARAMETER_MIX
;
349 is_ipv4
= tsocket_address_is_inet(remote_addr
, "ipv4");
350 is_ipv6
= tsocket_address_is_inet(remote_addr
, "ipv6");
354 } else if (is_ipv6
) {
357 return NT_STATUS_INVALID_ADDRESS
;
361 c
= talloc_zero(mem_ctx
, struct cldap_socket
);
368 * Here we know the address family of the remote address.
371 return NT_STATUS_INVALID_PARAMETER_MIX
;
374 ret
= tsocket_address_inet_from_strings(c
, fam
,
378 status
= map_nt_error_from_unix_common(errno
);
384 c
->searches
.idr
= idr_init(c
);
385 if (!c
->searches
.idr
) {
389 ret
= tdgram_inet_udp_socket(local_addr
, remote_addr
,
392 status
= map_nt_error_from_unix_common(errno
);
401 c
->send_queue
= tevent_queue_create(c
, "cldap_send_queue");
402 if (!c
->send_queue
) {
406 talloc_set_destructor(c
, cldap_socket_destructor
);
412 status
= NT_STATUS_NO_MEMORY
;
419 setup a handler for incoming requests
421 NTSTATUS
cldap_set_incoming_handler(struct cldap_socket
*c
,
422 struct tevent_context
*ev
,
423 void (*handler
)(struct cldap_socket
*,
425 struct cldap_incoming
*),
429 return NT_STATUS_PIPE_CONNECTED
;
433 c
->incoming
.handler
= handler
;
434 c
->incoming
.private_data
= private_data
;
436 if (!cldap_recvfrom_setup(c
)) {
437 ZERO_STRUCT(c
->incoming
);
438 return NT_STATUS_NO_MEMORY
;
444 struct cldap_reply_state
{
445 struct tsocket_address
*dest
;
449 static void cldap_reply_state_destroy(struct tevent_req
*subreq
);
452 queue a cldap reply for send
454 NTSTATUS
cldap_reply_send(struct cldap_socket
*cldap
, struct cldap_reply
*io
)
456 struct cldap_reply_state
*state
= NULL
;
457 struct ldap_message
*msg
;
458 DATA_BLOB blob1
, blob2
;
460 struct tevent_req
*subreq
;
462 if (cldap
->connected
) {
463 return NT_STATUS_PIPE_CONNECTED
;
466 if (cldap
->incoming
.ev
== NULL
) {
467 return NT_STATUS_INVALID_PIPE_STATE
;
471 return NT_STATUS_INVALID_ADDRESS
;
474 state
= talloc(cldap
, struct cldap_reply_state
);
475 NT_STATUS_HAVE_NO_MEMORY(state
);
477 state
->dest
= tsocket_address_copy(io
->dest
, state
);
482 msg
= talloc(state
, struct ldap_message
);
487 msg
->messageid
= io
->messageid
;
488 msg
->controls
= NULL
;
491 msg
->type
= LDAP_TAG_SearchResultEntry
;
492 msg
->r
.SearchResultEntry
= *io
->response
;
494 if (!ldap_encode(msg
, NULL
, &blob1
, state
)) {
495 status
= NT_STATUS_INVALID_PARAMETER
;
499 blob1
= data_blob(NULL
, 0);
502 msg
->type
= LDAP_TAG_SearchResultDone
;
503 msg
->r
.SearchResultDone
= *io
->result
;
505 if (!ldap_encode(msg
, NULL
, &blob2
, state
)) {
506 status
= NT_STATUS_INVALID_PARAMETER
;
511 state
->blob
= data_blob_talloc(state
, NULL
, blob1
.length
+ blob2
.length
);
512 if (!state
->blob
.data
) {
516 if (blob1
.data
!= NULL
) {
517 memcpy(state
->blob
.data
, blob1
.data
, blob1
.length
);
519 memcpy(state
->blob
.data
+blob1
.length
, blob2
.data
, blob2
.length
);
520 data_blob_free(&blob1
);
521 data_blob_free(&blob2
);
523 subreq
= tdgram_sendto_queue_send(state
,
533 /* the callback will just free the state, as we don't need a result */
534 tevent_req_set_callback(subreq
, cldap_reply_state_destroy
, state
);
539 status
= NT_STATUS_NO_MEMORY
;
545 static void cldap_reply_state_destroy(struct tevent_req
*subreq
)
547 struct cldap_reply_state
*state
= tevent_req_callback_data(subreq
,
548 struct cldap_reply_state
);
550 /* we don't want to know the result here, we just free the state */
555 static int cldap_search_state_destructor(struct cldap_search_state
*s
)
557 if (s
->caller
.cldap
) {
558 if (s
->message_id
!= -1) {
559 idr_remove(s
->caller
.cldap
->searches
.idr
, s
->message_id
);
562 DLIST_REMOVE(s
->caller
.cldap
->searches
.list
, s
);
563 cldap_recvfrom_stop(s
->caller
.cldap
);
564 ZERO_STRUCT(s
->caller
);
570 static void cldap_search_state_queue_done(struct tevent_req
*subreq
);
571 static void cldap_search_state_wakeup_done(struct tevent_req
*subreq
);
574 queue a cldap reply for send
576 struct tevent_req
*cldap_search_send(TALLOC_CTX
*mem_ctx
,
577 struct tevent_context
*ev
,
578 struct cldap_socket
*cldap
,
579 const struct cldap_search
*io
)
581 struct tevent_req
*req
, *subreq
;
582 struct cldap_search_state
*state
= NULL
;
583 struct ldap_message
*msg
;
584 struct ldap_SearchRequest
*search
;
590 req
= tevent_req_create(mem_ctx
, &state
,
591 struct cldap_search_state
);
595 state
->caller
.ev
= ev
;
597 state
->caller
.cldap
= cldap
;
598 state
->message_id
= -1;
600 talloc_set_destructor(state
, cldap_search_state_destructor
);
602 if (state
->caller
.cldap
== NULL
) {
603 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
607 if (io
->in
.dest_address
) {
608 if (cldap
->connected
) {
609 tevent_req_nterror(req
, NT_STATUS_PIPE_CONNECTED
);
612 ret
= tsocket_address_inet_from_strings(state
,
616 &state
->request
.dest
);
618 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
622 if (!cldap
->connected
) {
623 tevent_req_nterror(req
, NT_STATUS_INVALID_ADDRESS
);
626 state
->request
.dest
= NULL
;
629 state
->message_id
= idr_get_new_random(
630 cldap
->searches
.idr
, state
, 1, UINT16_MAX
);
631 if (state
->message_id
== -1) {
632 tevent_req_nterror(req
, NT_STATUS_INSUFFICIENT_RESOURCES
);
636 msg
= talloc(state
, struct ldap_message
);
637 if (tevent_req_nomem(msg
, req
)) {
641 msg
->messageid
= state
->message_id
;
642 msg
->type
= LDAP_TAG_SearchRequest
;
643 msg
->controls
= NULL
;
644 search
= &msg
->r
.SearchRequest
;
647 search
->scope
= LDAP_SEARCH_SCOPE_BASE
;
648 search
->deref
= LDAP_DEREFERENCE_NEVER
;
649 search
->timelimit
= 0;
650 search
->sizelimit
= 0;
651 search
->attributesonly
= false;
652 search
->num_attributes
= str_list_length(io
->in
.attributes
);
653 search
->attributes
= io
->in
.attributes
;
654 search
->tree
= ldb_parse_tree(msg
, io
->in
.filter
);
655 if (tevent_req_nomem(search
->tree
, req
)) {
659 if (!ldap_encode(msg
, NULL
, &state
->request
.blob
, state
)) {
660 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
665 state
->request
.idx
= 0;
666 state
->request
.delay
= 10*1000*1000;
667 state
->request
.count
= 3;
668 if (io
->in
.timeout
> 0) {
669 state
->request
.delay
= io
->in
.timeout
* 1000 * 1000;
670 state
->request
.count
= io
->in
.retries
+ 1;
673 now
= tevent_timeval_current();
675 for (i
= 0; i
< state
->request
.count
; i
++) {
676 end
= tevent_timeval_add(&end
, state
->request
.delay
/ 1000000,
677 state
->request
.delay
% 1000000);
680 if (!tevent_req_set_endtime(req
, state
->caller
.ev
, end
)) {
684 subreq
= tdgram_sendto_queue_send(state
,
686 state
->caller
.cldap
->sock
,
687 state
->caller
.cldap
->send_queue
,
688 state
->request
.blob
.data
,
689 state
->request
.blob
.length
,
690 state
->request
.dest
);
691 if (tevent_req_nomem(subreq
, req
)) {
694 tevent_req_set_callback(subreq
, cldap_search_state_queue_done
, req
);
696 DLIST_ADD_END(cldap
->searches
.list
, state
);
701 return tevent_req_post(req
, state
->caller
.ev
);
704 static void cldap_search_state_queue_done(struct tevent_req
*subreq
)
706 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
708 struct cldap_search_state
*state
= tevent_req_data(req
,
709 struct cldap_search_state
);
714 ret
= tdgram_sendto_queue_recv(subreq
, &sys_errno
);
718 status
= map_nt_error_from_unix_common(sys_errno
);
719 DLIST_REMOVE(state
->caller
.cldap
->searches
.list
, state
);
720 ZERO_STRUCT(state
->caller
.cldap
);
721 tevent_req_nterror(req
, status
);
725 state
->request
.idx
++;
727 /* wait for incoming traffic */
728 if (!cldap_recvfrom_setup(state
->caller
.cldap
)) {
733 if (state
->request
.idx
> state
->request
.count
) {
734 /* we just wait for the response or a timeout */
738 next
= tevent_timeval_current_ofs(state
->request
.delay
/ 1000000,
739 state
->request
.delay
% 1000000);
740 subreq
= tevent_wakeup_send(state
,
743 if (tevent_req_nomem(subreq
, req
)) {
746 tevent_req_set_callback(subreq
, cldap_search_state_wakeup_done
, req
);
749 static void cldap_search_state_wakeup_done(struct tevent_req
*subreq
)
751 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
753 struct cldap_search_state
*state
= tevent_req_data(req
,
754 struct cldap_search_state
);
757 ok
= tevent_wakeup_recv(subreq
);
760 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
764 subreq
= tdgram_sendto_queue_send(state
,
766 state
->caller
.cldap
->sock
,
767 state
->caller
.cldap
->send_queue
,
768 state
->request
.blob
.data
,
769 state
->request
.blob
.length
,
770 state
->request
.dest
);
771 if (tevent_req_nomem(subreq
, req
)) {
774 tevent_req_set_callback(subreq
, cldap_search_state_queue_done
, req
);
778 receive a cldap reply
780 NTSTATUS
cldap_search_recv(struct tevent_req
*req
,
782 struct cldap_search
*io
)
784 struct cldap_search_state
*state
= tevent_req_data(req
,
785 struct cldap_search_state
);
786 struct ldap_message
*ldap_msg
;
788 struct ldap_request_limits limits
= {
789 .max_search_size
= MAX_SEARCH_REQUEST
792 if (tevent_req_is_nterror(req
, &status
)) {
796 ldap_msg
= talloc(mem_ctx
, struct ldap_message
);
801 status
= ldap_decode(state
->response
.asn1
, &limits
, NULL
, ldap_msg
);
802 if (!NT_STATUS_IS_OK(status
)) {
806 ZERO_STRUCT(io
->out
);
808 /* the first possible form has a search result in first place */
809 if (ldap_msg
->type
== LDAP_TAG_SearchResultEntry
) {
810 io
->out
.response
= talloc(mem_ctx
, struct ldap_SearchResEntry
);
811 if (!io
->out
.response
) {
814 *io
->out
.response
= ldap_msg
->r
.SearchResultEntry
;
816 /* decode the 2nd part */
817 status
= ldap_decode(
818 state
->response
.asn1
, &limits
, NULL
, ldap_msg
);
819 if (!NT_STATUS_IS_OK(status
)) {
824 if (ldap_msg
->type
!= LDAP_TAG_SearchResultDone
) {
825 status
= NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR
);
829 io
->out
.result
= talloc(mem_ctx
, struct ldap_Result
);
830 if (!io
->out
.result
) {
833 *io
->out
.result
= ldap_msg
->r
.SearchResultDone
;
835 if (io
->out
.result
->resultcode
!= LDAP_SUCCESS
) {
836 status
= NT_STATUS_LDAP(io
->out
.result
->resultcode
);
840 tevent_req_received(req
);
844 status
= NT_STATUS_NO_MEMORY
;
846 tevent_req_received(req
);
852 synchronous cldap search
854 NTSTATUS
cldap_search(struct cldap_socket
*cldap
,
856 struct cldap_search
*io
)
859 struct tevent_req
*req
;
860 struct tevent_context
*ev
;
863 if (cldap
->searches
.list
) {
864 return NT_STATUS_PIPE_BUSY
;
867 if (cldap
->incoming
.handler
) {
868 return NT_STATUS_INVALID_PIPE_STATE
;
871 frame
= talloc_stackframe();
873 ev
= samba_tevent_context_init(frame
);
876 return NT_STATUS_NO_MEMORY
;
879 req
= cldap_search_send(mem_ctx
, ev
, cldap
, io
);
882 return NT_STATUS_NO_MEMORY
;
885 if (!tevent_req_poll(req
, ev
)) {
886 status
= map_nt_error_from_unix_common(errno
);
891 status
= cldap_search_recv(req
, mem_ctx
, io
);
892 if (!NT_STATUS_IS_OK(status
)) {
901 struct cldap_netlogon_state
{
902 struct cldap_search search
;
905 char *cldap_netlogon_create_filter(TALLOC_CTX
*mem_ctx
,
906 const struct cldap_netlogon
*io
)
910 filter
= talloc_asprintf(mem_ctx
, "(&(NtVer=%s)",
911 ldap_encode_ndr_uint32(mem_ctx
, io
->in
.version
));
914 talloc_asprintf_addbuf(&filter
, "(User=%s)", io
->in
.user
);
917 talloc_asprintf_addbuf(&filter
, "(Host=%s)", io
->in
.host
);
920 talloc_asprintf_addbuf(&filter
, "(DnsDomain=%s)", io
->in
.realm
);
922 if (io
->in
.acct_control
!= -1) {
923 talloc_asprintf_addbuf(
926 ldap_encode_ndr_uint32(mem_ctx
, io
->in
.acct_control
));
928 if (io
->in
.domain_sid
) {
929 struct dom_sid
*sid
= dom_sid_parse_talloc(mem_ctx
, io
->in
.domain_sid
);
931 talloc_asprintf_addbuf(&filter
, "(domainSid=%s)",
932 ldap_encode_ndr_dom_sid(mem_ctx
, sid
));
934 if (io
->in
.domain_guid
) {
936 GUID_from_string(io
->in
.domain_guid
, &guid
);
938 talloc_asprintf_addbuf(&filter
, "(DomainGuid=%s)",
939 ldap_encode_ndr_GUID(mem_ctx
, &guid
));
941 talloc_asprintf_addbuf(&filter
, ")");
946 static void cldap_netlogon_state_done(struct tevent_req
*subreq
);
948 queue a cldap netlogon for send
950 struct tevent_req
*cldap_netlogon_send(TALLOC_CTX
*mem_ctx
,
951 struct tevent_context
*ev
,
952 struct cldap_socket
*cldap
,
953 const struct cldap_netlogon
*io
)
955 struct tevent_req
*req
, *subreq
;
956 struct cldap_netlogon_state
*state
;
958 static const char * const attr
[] = { "NetLogon", NULL
};
960 req
= tevent_req_create(mem_ctx
, &state
,
961 struct cldap_netlogon_state
);
966 filter
= cldap_netlogon_create_filter(state
, io
);
967 if (tevent_req_nomem(filter
, req
)) {
971 if (io
->in
.dest_address
) {
972 state
->search
.in
.dest_address
= talloc_strdup(state
,
973 io
->in
.dest_address
);
974 if (tevent_req_nomem(state
->search
.in
.dest_address
, req
)) {
977 state
->search
.in
.dest_port
= io
->in
.dest_port
;
979 state
->search
.in
.dest_address
= NULL
;
980 state
->search
.in
.dest_port
= 0;
982 state
->search
.in
.filter
= filter
;
983 state
->search
.in
.attributes
= attr
;
984 state
->search
.in
.timeout
= 2;
985 state
->search
.in
.retries
= 2;
987 subreq
= cldap_search_send(state
, ev
, cldap
, &state
->search
);
988 if (tevent_req_nomem(subreq
, req
)) {
991 tevent_req_set_callback(subreq
, cldap_netlogon_state_done
, req
);
995 return tevent_req_post(req
, ev
);
998 static void cldap_netlogon_state_done(struct tevent_req
*subreq
)
1000 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
1002 struct cldap_netlogon_state
*state
= tevent_req_data(req
,
1003 struct cldap_netlogon_state
);
1006 status
= cldap_search_recv(subreq
, state
, &state
->search
);
1007 talloc_free(subreq
);
1009 if (tevent_req_nterror(req
, status
)) {
1013 tevent_req_done(req
);
1017 receive a cldap netlogon reply
1019 NTSTATUS
cldap_netlogon_recv(struct tevent_req
*req
,
1020 TALLOC_CTX
*mem_ctx
,
1021 struct cldap_netlogon
*io
)
1023 struct cldap_netlogon_state
*state
= tevent_req_data(req
,
1024 struct cldap_netlogon_state
);
1025 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1028 if (tevent_req_is_nterror(req
, &status
)) {
1032 if (state
->search
.out
.response
== NULL
) {
1033 status
= NT_STATUS_NOT_FOUND
;
1037 if (state
->search
.out
.response
->num_attributes
!= 1 ||
1038 strcasecmp(state
->search
.out
.response
->attributes
[0].name
, "netlogon") != 0 ||
1039 state
->search
.out
.response
->attributes
[0].num_values
!= 1 ||
1040 state
->search
.out
.response
->attributes
[0].values
->length
< 2) {
1041 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
1044 data
= state
->search
.out
.response
->attributes
[0].values
;
1046 status
= pull_netlogon_samlogon_response(data
, mem_ctx
,
1048 if (!NT_STATUS_IS_OK(status
)) {
1052 if (io
->in
.map_response
) {
1053 map_netlogon_samlogon_response(&io
->out
.netlogon
);
1056 status
= NT_STATUS_OK
;
1058 tevent_req_received(req
);
1063 sync cldap netlogon search
1065 NTSTATUS
cldap_netlogon(struct cldap_socket
*cldap
,
1066 TALLOC_CTX
*mem_ctx
,
1067 struct cldap_netlogon
*io
)
1070 struct tevent_req
*req
;
1071 struct tevent_context
*ev
;
1074 if (cldap
->searches
.list
) {
1075 return NT_STATUS_PIPE_BUSY
;
1078 if (cldap
->incoming
.handler
) {
1079 return NT_STATUS_INVALID_PIPE_STATE
;
1082 frame
= talloc_stackframe();
1084 ev
= samba_tevent_context_init(frame
);
1087 return NT_STATUS_NO_MEMORY
;
1090 req
= cldap_netlogon_send(mem_ctx
, ev
, cldap
, io
);
1093 return NT_STATUS_NO_MEMORY
;
1096 if (!tevent_req_poll(req
, ev
)) {
1097 status
= map_nt_error_from_unix_common(errno
);
1102 status
= cldap_netlogon_recv(req
, mem_ctx
, io
);
1103 if (!NT_STATUS_IS_OK(status
)) {
1109 return NT_STATUS_OK
;
1114 send an empty reply (used on any error, so the client doesn't keep waiting
1115 or send the bad request again)
1117 NTSTATUS
cldap_empty_reply(struct cldap_socket
*cldap
,
1118 uint32_t message_id
,
1119 struct tsocket_address
*dest
)
1122 struct cldap_reply reply
;
1123 struct ldap_Result result
;
1125 reply
.messageid
= message_id
;
1127 reply
.response
= NULL
;
1128 reply
.result
= &result
;
1130 ZERO_STRUCT(result
);
1132 status
= cldap_reply_send(cldap
, &reply
);
1138 send an error reply (used on any error, so the client doesn't keep waiting
1139 or send the bad request again)
1141 NTSTATUS
cldap_error_reply(struct cldap_socket
*cldap
,
1142 uint32_t message_id
,
1143 struct tsocket_address
*dest
,
1145 const char *errormessage
)
1148 struct cldap_reply reply
;
1149 struct ldap_Result result
;
1151 reply
.messageid
= message_id
;
1153 reply
.response
= NULL
;
1154 reply
.result
= &result
;
1156 ZERO_STRUCT(result
);
1157 result
.resultcode
= resultcode
;
1158 result
.errormessage
= errormessage
;
1160 status
= cldap_reply_send(cldap
, &reply
);
1167 send a netlogon reply
1169 NTSTATUS
cldap_netlogon_reply(struct cldap_socket
*cldap
,
1170 uint32_t message_id
,
1171 struct tsocket_address
*dest
,
1173 struct netlogon_samlogon_response
*netlogon
)
1176 struct cldap_reply reply
;
1177 struct ldap_SearchResEntry response
;
1178 struct ldap_Result result
;
1179 TALLOC_CTX
*tmp_ctx
= talloc_new(cldap
);
1182 status
= push_netlogon_samlogon_response(&blob
, tmp_ctx
,
1184 if (!NT_STATUS_IS_OK(status
)) {
1185 talloc_free(tmp_ctx
);
1188 reply
.messageid
= message_id
;
1190 reply
.response
= &response
;
1191 reply
.result
= &result
;
1193 ZERO_STRUCT(result
);
1196 response
.num_attributes
= 1;
1197 response
.attributes
= talloc(tmp_ctx
, struct ldb_message_element
);
1198 NT_STATUS_HAVE_NO_MEMORY(response
.attributes
);
1199 response
.attributes
->name
= "netlogon";
1200 response
.attributes
->num_values
= 1;
1201 response
.attributes
->values
= &blob
;
1203 status
= cldap_reply_send(cldap
, &reply
);
1205 talloc_free(tmp_ctx
);