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
)) {
218 handle recv events on a cldap socket
220 static bool cldap_socket_recv_dgram(struct cldap_socket
*c
,
221 struct cldap_incoming
*in
)
224 struct asn1_data
*asn1
;
226 struct cldap_search_state
*search
;
229 if (in
->recv_errno
!= 0) {
233 blob
= data_blob_const(in
->buf
, in
->len
);
235 asn1
= asn1_init(in
);
240 if (!asn1_load(asn1
, blob
)) {
244 in
->ldap_msg
= talloc(in
, struct ldap_message
);
245 if (in
->ldap_msg
== NULL
) {
249 /* this initial decode is used to find the message id */
250 status
= ldap_decode(asn1
, NULL
, in
->ldap_msg
);
251 if (!NT_STATUS_IS_OK(status
)) {
255 /* find the pending request */
256 p
= idr_find(c
->searches
.idr
, in
->ldap_msg
->messageid
);
258 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_abort(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 DLIST_REMOVE(c
->searches
.list
, search
);
275 if (cldap_recvfrom_setup(c
)) {
276 tevent_req_done(search
->req
);
281 * This request was ok, just defer the notify of the caller
282 * and then just fail the next request if needed
284 tevent_req_defer_callback(search
->req
, search
->caller
.ev
);
285 tevent_req_done(search
->req
);
287 status
= NT_STATUS_NO_MEMORY
;
288 /* in is NULL it this point */
291 in
->recv_errno
= ENOMEM
;
293 status
= map_nt_error_from_unix_common(in
->recv_errno
);
296 /* in connected mode the first pending search gets the error */
298 /* otherwise we just ignore the error */
301 if (!c
->searches
.list
) {
305 * We might called tevent_req_done() for a successful
306 * search before, so we better deliver the failure
307 * after the success, that is why we better also
308 * use tevent_req_defer_callback() here.
310 tevent_req_defer_callback(c
->searches
.list
->req
,
311 c
->searches
.list
->caller
.ev
);
312 tevent_req_nterror(c
->searches
.list
->req
, status
);
317 initialise a cldap_sock
319 NTSTATUS
cldap_socket_init(TALLOC_CTX
*mem_ctx
,
320 const struct tsocket_address
*local_addr
,
321 const struct tsocket_address
*remote_addr
,
322 struct cldap_socket
**_cldap
)
324 struct cldap_socket
*c
= NULL
;
325 struct tsocket_address
*any
= NULL
;
328 const char *fam
= NULL
;
330 if (local_addr
== NULL
&& remote_addr
== NULL
) {
331 return NT_STATUS_INVALID_PARAMETER_MIX
;
338 is_ipv4
= tsocket_address_is_inet(remote_addr
, "ipv4");
339 is_ipv6
= tsocket_address_is_inet(remote_addr
, "ipv6");
343 } else if (is_ipv6
) {
346 return NT_STATUS_INVALID_ADDRESS
;
350 c
= talloc_zero(mem_ctx
, struct cldap_socket
);
357 * Here we know the address family of the remote address.
360 return NT_STATUS_INVALID_PARAMETER_MIX
;
363 ret
= tsocket_address_inet_from_strings(c
, fam
,
367 status
= map_nt_error_from_unix_common(errno
);
373 c
->searches
.idr
= idr_init(c
);
374 if (!c
->searches
.idr
) {
378 ret
= tdgram_inet_udp_socket(local_addr
, remote_addr
,
381 status
= map_nt_error_from_unix_common(errno
);
390 c
->send_queue
= tevent_queue_create(c
, "cldap_send_queue");
391 if (!c
->send_queue
) {
395 talloc_set_destructor(c
, cldap_socket_destructor
);
401 status
= NT_STATUS_NO_MEMORY
;
408 setup a handler for incoming requests
410 NTSTATUS
cldap_set_incoming_handler(struct cldap_socket
*c
,
411 struct tevent_context
*ev
,
412 void (*handler
)(struct cldap_socket
*,
414 struct cldap_incoming
*),
418 return NT_STATUS_PIPE_CONNECTED
;
422 c
->incoming
.handler
= handler
;
423 c
->incoming
.private_data
= private_data
;
425 if (!cldap_recvfrom_setup(c
)) {
426 ZERO_STRUCT(c
->incoming
);
427 return NT_STATUS_NO_MEMORY
;
433 struct cldap_reply_state
{
434 struct tsocket_address
*dest
;
438 static void cldap_reply_state_destroy(struct tevent_req
*subreq
);
441 queue a cldap reply for send
443 NTSTATUS
cldap_reply_send(struct cldap_socket
*cldap
, struct cldap_reply
*io
)
445 struct cldap_reply_state
*state
= NULL
;
446 struct ldap_message
*msg
;
447 DATA_BLOB blob1
, blob2
;
449 struct tevent_req
*subreq
;
451 if (cldap
->connected
) {
452 return NT_STATUS_PIPE_CONNECTED
;
455 if (cldap
->incoming
.ev
== NULL
) {
456 return NT_STATUS_INVALID_PIPE_STATE
;
460 return NT_STATUS_INVALID_ADDRESS
;
463 state
= talloc(cldap
, struct cldap_reply_state
);
464 NT_STATUS_HAVE_NO_MEMORY(state
);
466 state
->dest
= tsocket_address_copy(io
->dest
, state
);
471 msg
= talloc(state
, struct ldap_message
);
476 msg
->messageid
= io
->messageid
;
477 msg
->controls
= NULL
;
480 msg
->type
= LDAP_TAG_SearchResultEntry
;
481 msg
->r
.SearchResultEntry
= *io
->response
;
483 if (!ldap_encode(msg
, NULL
, &blob1
, state
)) {
484 status
= NT_STATUS_INVALID_PARAMETER
;
488 blob1
= data_blob(NULL
, 0);
491 msg
->type
= LDAP_TAG_SearchResultDone
;
492 msg
->r
.SearchResultDone
= *io
->result
;
494 if (!ldap_encode(msg
, NULL
, &blob2
, state
)) {
495 status
= NT_STATUS_INVALID_PARAMETER
;
500 state
->blob
= data_blob_talloc(state
, NULL
, blob1
.length
+ blob2
.length
);
501 if (!state
->blob
.data
) {
505 memcpy(state
->blob
.data
, blob1
.data
, blob1
.length
);
506 memcpy(state
->blob
.data
+blob1
.length
, blob2
.data
, blob2
.length
);
507 data_blob_free(&blob1
);
508 data_blob_free(&blob2
);
510 subreq
= tdgram_sendto_queue_send(state
,
520 /* the callback will just free the state, as we don't need a result */
521 tevent_req_set_callback(subreq
, cldap_reply_state_destroy
, state
);
526 status
= NT_STATUS_NO_MEMORY
;
532 static void cldap_reply_state_destroy(struct tevent_req
*subreq
)
534 struct cldap_reply_state
*state
= tevent_req_callback_data(subreq
,
535 struct cldap_reply_state
);
537 /* we don't want to know the result here, we just free the state */
542 static int cldap_search_state_destructor(struct cldap_search_state
*s
)
544 if (s
->caller
.cldap
) {
545 if (s
->message_id
!= -1) {
546 idr_remove(s
->caller
.cldap
->searches
.idr
, s
->message_id
);
549 DLIST_REMOVE(s
->caller
.cldap
->searches
.list
, s
);
550 cldap_recvfrom_stop(s
->caller
.cldap
);
551 ZERO_STRUCT(s
->caller
);
557 static void cldap_search_state_queue_done(struct tevent_req
*subreq
);
558 static void cldap_search_state_wakeup_done(struct tevent_req
*subreq
);
561 queue a cldap reply for send
563 struct tevent_req
*cldap_search_send(TALLOC_CTX
*mem_ctx
,
564 struct tevent_context
*ev
,
565 struct cldap_socket
*cldap
,
566 const struct cldap_search
*io
)
568 struct tevent_req
*req
, *subreq
;
569 struct cldap_search_state
*state
= NULL
;
570 struct ldap_message
*msg
;
571 struct ldap_SearchRequest
*search
;
577 req
= tevent_req_create(mem_ctx
, &state
,
578 struct cldap_search_state
);
583 state
->caller
.ev
= ev
;
585 state
->caller
.cldap
= cldap
;
586 state
->message_id
= -1;
588 talloc_set_destructor(state
, cldap_search_state_destructor
);
590 if (io
->in
.dest_address
) {
591 if (cldap
->connected
) {
592 tevent_req_nterror(req
, NT_STATUS_PIPE_CONNECTED
);
595 ret
= tsocket_address_inet_from_strings(state
,
599 &state
->request
.dest
);
601 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
605 if (!cldap
->connected
) {
606 tevent_req_nterror(req
, NT_STATUS_INVALID_ADDRESS
);
609 state
->request
.dest
= NULL
;
612 state
->message_id
= idr_get_new_random(cldap
->searches
.idr
,
614 if (state
->message_id
== -1) {
615 tevent_req_nterror(req
, NT_STATUS_INSUFFICIENT_RESOURCES
);
619 msg
= talloc(state
, struct ldap_message
);
620 if (tevent_req_nomem(msg
, req
)) {
624 msg
->messageid
= state
->message_id
;
625 msg
->type
= LDAP_TAG_SearchRequest
;
626 msg
->controls
= NULL
;
627 search
= &msg
->r
.SearchRequest
;
630 search
->scope
= LDAP_SEARCH_SCOPE_BASE
;
631 search
->deref
= LDAP_DEREFERENCE_NEVER
;
632 search
->timelimit
= 0;
633 search
->sizelimit
= 0;
634 search
->attributesonly
= false;
635 search
->num_attributes
= str_list_length(io
->in
.attributes
);
636 search
->attributes
= io
->in
.attributes
;
637 search
->tree
= ldb_parse_tree(msg
, io
->in
.filter
);
638 if (tevent_req_nomem(search
->tree
, req
)) {
642 if (!ldap_encode(msg
, NULL
, &state
->request
.blob
, state
)) {
643 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
648 state
->request
.idx
= 0;
649 state
->request
.delay
= 10*1000*1000;
650 state
->request
.count
= 3;
651 if (io
->in
.timeout
> 0) {
652 state
->request
.delay
= io
->in
.timeout
* 1000 * 1000;
653 state
->request
.count
= io
->in
.retries
+ 1;
656 now
= tevent_timeval_current();
658 for (i
= 0; i
< state
->request
.count
; i
++) {
659 end
= tevent_timeval_add(&end
, state
->request
.delay
/ 1000000,
660 state
->request
.delay
% 1000000);
663 if (!tevent_req_set_endtime(req
, state
->caller
.ev
, end
)) {
668 subreq
= tdgram_sendto_queue_send(state
,
670 state
->caller
.cldap
->sock
,
671 state
->caller
.cldap
->send_queue
,
672 state
->request
.blob
.data
,
673 state
->request
.blob
.length
,
674 state
->request
.dest
);
675 if (tevent_req_nomem(subreq
, req
)) {
678 tevent_req_set_callback(subreq
, cldap_search_state_queue_done
, req
);
680 DLIST_ADD_END(cldap
->searches
.list
, state
, struct cldap_search_state
*);
685 return tevent_req_post(req
, state
->caller
.ev
);
688 static void cldap_search_state_queue_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
);
698 ret
= tdgram_sendto_queue_recv(subreq
, &sys_errno
);
702 status
= map_nt_error_from_unix_common(sys_errno
);
703 DLIST_REMOVE(state
->caller
.cldap
->searches
.list
, state
);
704 ZERO_STRUCT(state
->caller
.cldap
);
705 tevent_req_nterror(req
, status
);
709 state
->request
.idx
++;
711 /* wait for incoming traffic */
712 if (!cldap_recvfrom_setup(state
->caller
.cldap
)) {
717 if (state
->request
.idx
> state
->request
.count
) {
718 /* we just wait for the response or a timeout */
722 next
= tevent_timeval_current_ofs(state
->request
.delay
/ 1000000,
723 state
->request
.delay
% 1000000);
724 subreq
= tevent_wakeup_send(state
,
727 if (tevent_req_nomem(subreq
, req
)) {
730 tevent_req_set_callback(subreq
, cldap_search_state_wakeup_done
, req
);
733 static void cldap_search_state_wakeup_done(struct tevent_req
*subreq
)
735 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
737 struct cldap_search_state
*state
= tevent_req_data(req
,
738 struct cldap_search_state
);
741 ok
= tevent_wakeup_recv(subreq
);
744 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
748 subreq
= tdgram_sendto_queue_send(state
,
750 state
->caller
.cldap
->sock
,
751 state
->caller
.cldap
->send_queue
,
752 state
->request
.blob
.data
,
753 state
->request
.blob
.length
,
754 state
->request
.dest
);
755 if (tevent_req_nomem(subreq
, req
)) {
758 tevent_req_set_callback(subreq
, cldap_search_state_queue_done
, req
);
762 receive a cldap reply
764 NTSTATUS
cldap_search_recv(struct tevent_req
*req
,
766 struct cldap_search
*io
)
768 struct cldap_search_state
*state
= tevent_req_data(req
,
769 struct cldap_search_state
);
770 struct ldap_message
*ldap_msg
;
773 if (tevent_req_is_nterror(req
, &status
)) {
777 ldap_msg
= talloc(mem_ctx
, struct ldap_message
);
782 status
= ldap_decode(state
->response
.asn1
, NULL
, ldap_msg
);
783 if (!NT_STATUS_IS_OK(status
)) {
787 ZERO_STRUCT(io
->out
);
789 /* the first possible form has a search result in first place */
790 if (ldap_msg
->type
== LDAP_TAG_SearchResultEntry
) {
791 io
->out
.response
= talloc(mem_ctx
, struct ldap_SearchResEntry
);
792 if (!io
->out
.response
) {
795 *io
->out
.response
= ldap_msg
->r
.SearchResultEntry
;
797 /* decode the 2nd part */
798 status
= ldap_decode(state
->response
.asn1
, NULL
, ldap_msg
);
799 if (!NT_STATUS_IS_OK(status
)) {
804 if (ldap_msg
->type
!= LDAP_TAG_SearchResultDone
) {
805 status
= NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR
);
809 io
->out
.result
= talloc(mem_ctx
, struct ldap_Result
);
810 if (!io
->out
.result
) {
813 *io
->out
.result
= ldap_msg
->r
.SearchResultDone
;
815 if (io
->out
.result
->resultcode
!= LDAP_SUCCESS
) {
816 status
= NT_STATUS_LDAP(io
->out
.result
->resultcode
);
820 tevent_req_received(req
);
824 status
= NT_STATUS_NO_MEMORY
;
826 tevent_req_received(req
);
832 synchronous cldap search
834 NTSTATUS
cldap_search(struct cldap_socket
*cldap
,
836 struct cldap_search
*io
)
839 struct tevent_req
*req
;
840 struct tevent_context
*ev
;
843 if (cldap
->searches
.list
) {
844 return NT_STATUS_PIPE_BUSY
;
847 if (cldap
->incoming
.handler
) {
848 return NT_STATUS_INVALID_PIPE_STATE
;
851 frame
= talloc_stackframe();
853 ev
= samba_tevent_context_init(frame
);
856 return NT_STATUS_NO_MEMORY
;
859 req
= cldap_search_send(mem_ctx
, ev
, cldap
, io
);
862 return NT_STATUS_NO_MEMORY
;
865 if (!tevent_req_poll(req
, ev
)) {
866 status
= map_nt_error_from_unix_common(errno
);
871 status
= cldap_search_recv(req
, mem_ctx
, io
);
872 if (!NT_STATUS_IS_OK(status
)) {
881 struct cldap_netlogon_state
{
882 struct cldap_search search
;
885 static void cldap_netlogon_state_done(struct tevent_req
*subreq
);
887 queue a cldap netlogon for send
889 struct tevent_req
*cldap_netlogon_send(TALLOC_CTX
*mem_ctx
,
890 struct tevent_context
*ev
,
891 struct cldap_socket
*cldap
,
892 const struct cldap_netlogon
*io
)
894 struct tevent_req
*req
, *subreq
;
895 struct cldap_netlogon_state
*state
;
897 static const char * const attr
[] = { "NetLogon", NULL
};
899 req
= tevent_req_create(mem_ctx
, &state
,
900 struct cldap_netlogon_state
);
905 filter
= talloc_asprintf(state
, "(&(NtVer=%s)",
906 ldap_encode_ndr_uint32(state
, io
->in
.version
));
907 if (tevent_req_nomem(filter
, req
)) {
911 filter
= talloc_asprintf_append_buffer(filter
, "(User=%s)", io
->in
.user
);
912 if (tevent_req_nomem(filter
, req
)) {
917 filter
= talloc_asprintf_append_buffer(filter
, "(Host=%s)", io
->in
.host
);
918 if (tevent_req_nomem(filter
, req
)) {
923 filter
= talloc_asprintf_append_buffer(filter
, "(DnsDomain=%s)", io
->in
.realm
);
924 if (tevent_req_nomem(filter
, req
)) {
928 if (io
->in
.acct_control
!= -1) {
929 filter
= talloc_asprintf_append_buffer(filter
, "(AAC=%s)",
930 ldap_encode_ndr_uint32(state
, io
->in
.acct_control
));
931 if (tevent_req_nomem(filter
, req
)) {
935 if (io
->in
.domain_sid
) {
936 struct dom_sid
*sid
= dom_sid_parse_talloc(state
, io
->in
.domain_sid
);
937 if (tevent_req_nomem(sid
, req
)) {
940 filter
= talloc_asprintf_append_buffer(filter
, "(domainSid=%s)",
941 ldap_encode_ndr_dom_sid(state
, sid
));
942 if (tevent_req_nomem(filter
, req
)) {
946 if (io
->in
.domain_guid
) {
949 status
= GUID_from_string(io
->in
.domain_guid
, &guid
);
950 if (tevent_req_nterror(req
, status
)) {
953 filter
= talloc_asprintf_append_buffer(filter
, "(DomainGuid=%s)",
954 ldap_encode_ndr_GUID(state
, &guid
));
955 if (tevent_req_nomem(filter
, req
)) {
959 filter
= talloc_asprintf_append_buffer(filter
, ")");
960 if (tevent_req_nomem(filter
, req
)) {
964 if (io
->in
.dest_address
) {
965 state
->search
.in
.dest_address
= talloc_strdup(state
,
966 io
->in
.dest_address
);
967 if (tevent_req_nomem(state
->search
.in
.dest_address
, req
)) {
970 state
->search
.in
.dest_port
= io
->in
.dest_port
;
972 state
->search
.in
.dest_address
= NULL
;
973 state
->search
.in
.dest_port
= 0;
975 state
->search
.in
.filter
= filter
;
976 state
->search
.in
.attributes
= attr
;
977 state
->search
.in
.timeout
= 2;
978 state
->search
.in
.retries
= 2;
980 subreq
= cldap_search_send(state
, ev
, cldap
, &state
->search
);
981 if (tevent_req_nomem(subreq
, req
)) {
984 tevent_req_set_callback(subreq
, cldap_netlogon_state_done
, req
);
988 return tevent_req_post(req
, ev
);
991 static void cldap_netlogon_state_done(struct tevent_req
*subreq
)
993 struct tevent_req
*req
= tevent_req_callback_data(subreq
,
995 struct cldap_netlogon_state
*state
= tevent_req_data(req
,
996 struct cldap_netlogon_state
);
999 status
= cldap_search_recv(subreq
, state
, &state
->search
);
1000 talloc_free(subreq
);
1002 if (tevent_req_nterror(req
, status
)) {
1006 tevent_req_done(req
);
1010 receive a cldap netlogon reply
1012 NTSTATUS
cldap_netlogon_recv(struct tevent_req
*req
,
1013 TALLOC_CTX
*mem_ctx
,
1014 struct cldap_netlogon
*io
)
1016 struct cldap_netlogon_state
*state
= tevent_req_data(req
,
1017 struct cldap_netlogon_state
);
1021 if (tevent_req_is_nterror(req
, &status
)) {
1025 if (state
->search
.out
.response
== NULL
) {
1026 status
= NT_STATUS_NOT_FOUND
;
1030 if (state
->search
.out
.response
->num_attributes
!= 1 ||
1031 strcasecmp(state
->search
.out
.response
->attributes
[0].name
, "netlogon") != 0 ||
1032 state
->search
.out
.response
->attributes
[0].num_values
!= 1 ||
1033 state
->search
.out
.response
->attributes
[0].values
->length
< 2) {
1034 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
1037 data
= state
->search
.out
.response
->attributes
[0].values
;
1039 status
= pull_netlogon_samlogon_response(data
, mem_ctx
,
1041 if (!NT_STATUS_IS_OK(status
)) {
1045 if (io
->in
.map_response
) {
1046 map_netlogon_samlogon_response(&io
->out
.netlogon
);
1049 status
= NT_STATUS_OK
;
1051 tevent_req_received(req
);
1056 sync cldap netlogon search
1058 NTSTATUS
cldap_netlogon(struct cldap_socket
*cldap
,
1059 TALLOC_CTX
*mem_ctx
,
1060 struct cldap_netlogon
*io
)
1063 struct tevent_req
*req
;
1064 struct tevent_context
*ev
;
1067 if (cldap
->searches
.list
) {
1068 return NT_STATUS_PIPE_BUSY
;
1071 if (cldap
->incoming
.handler
) {
1072 return NT_STATUS_INVALID_PIPE_STATE
;
1075 frame
= talloc_stackframe();
1077 ev
= samba_tevent_context_init(frame
);
1080 return NT_STATUS_NO_MEMORY
;
1083 req
= cldap_netlogon_send(mem_ctx
, ev
, cldap
, io
);
1086 return NT_STATUS_NO_MEMORY
;
1089 if (!tevent_req_poll(req
, ev
)) {
1090 status
= map_nt_error_from_unix_common(errno
);
1095 status
= cldap_netlogon_recv(req
, mem_ctx
, io
);
1096 if (!NT_STATUS_IS_OK(status
)) {
1102 return NT_STATUS_OK
;
1107 send an empty reply (used on any error, so the client doesn't keep waiting
1108 or send the bad request again)
1110 NTSTATUS
cldap_empty_reply(struct cldap_socket
*cldap
,
1111 uint32_t message_id
,
1112 struct tsocket_address
*dest
)
1115 struct cldap_reply reply
;
1116 struct ldap_Result result
;
1118 reply
.messageid
= message_id
;
1120 reply
.response
= NULL
;
1121 reply
.result
= &result
;
1123 ZERO_STRUCT(result
);
1125 status
= cldap_reply_send(cldap
, &reply
);
1131 send an error reply (used on any error, so the client doesn't keep waiting
1132 or send the bad request again)
1134 NTSTATUS
cldap_error_reply(struct cldap_socket
*cldap
,
1135 uint32_t message_id
,
1136 struct tsocket_address
*dest
,
1138 const char *errormessage
)
1141 struct cldap_reply reply
;
1142 struct ldap_Result result
;
1144 reply
.messageid
= message_id
;
1146 reply
.response
= NULL
;
1147 reply
.result
= &result
;
1149 ZERO_STRUCT(result
);
1150 result
.resultcode
= resultcode
;
1151 result
.errormessage
= errormessage
;
1153 status
= cldap_reply_send(cldap
, &reply
);
1160 send a netlogon reply
1162 NTSTATUS
cldap_netlogon_reply(struct cldap_socket
*cldap
,
1163 uint32_t message_id
,
1164 struct tsocket_address
*dest
,
1166 struct netlogon_samlogon_response
*netlogon
)
1169 struct cldap_reply reply
;
1170 struct ldap_SearchResEntry response
;
1171 struct ldap_Result result
;
1172 TALLOC_CTX
*tmp_ctx
= talloc_new(cldap
);
1175 status
= push_netlogon_samlogon_response(&blob
, tmp_ctx
,
1177 if (!NT_STATUS_IS_OK(status
)) {
1178 talloc_free(tmp_ctx
);
1181 reply
.messageid
= message_id
;
1183 reply
.response
= &response
;
1184 reply
.result
= &result
;
1186 ZERO_STRUCT(result
);
1189 response
.num_attributes
= 1;
1190 response
.attributes
= talloc(tmp_ctx
, struct ldb_message_element
);
1191 NT_STATUS_HAVE_NO_MEMORY(response
.attributes
);
1192 response
.attributes
->name
= "netlogon";
1193 response
.attributes
->num_values
= 1;
1194 response
.attributes
->values
= &blob
;
1196 status
= cldap_reply_send(cldap
, &reply
);
1198 talloc_free(tmp_ctx
);