libcli/auth: let netlogon_creds_copy() make use of ndr_deepcopy_struct()
[samba4-gss.git] / source3 / libads / netlogon_ping.c
blobc94af8fbc57f2d529d8970b08b1abe36c8796e88
1 /*
2 * Samba Unix/Linux SMB client library
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "replace.h"
19 #include <tevent.h>
20 #include "netlogon_ping.h"
21 #include "libcli/netlogon/netlogon_proto.h"
22 #include "libcli/ldap/ldap_ndr.h"
23 #include "libcli/ldap/ldap_message.h"
24 #include "libcli/cldap/cldap.h"
25 #include "source3/include/tldap.h"
26 #include "source3/include/tldap_util.h"
27 #include "source3/lib/tldap_tls_connect.h"
28 #include "lib/util/tevent_unix.h"
29 #include "lib/util/tevent_ntstatus.h"
30 #include "source4/lib/tls/tls.h"
31 #include "source3/libads/cldap.h"
32 #include "librpc/gen_ndr/netlogon.h"
34 #define RETURN_ON_FALSE(x) \
35 if (!(x)) \
36 return false;
38 bool check_cldap_reply_required_flags(uint32_t ret_flags, uint32_t req_flags)
40 if (req_flags == 0) {
41 return true;
44 if (req_flags & DS_PDC_REQUIRED)
45 RETURN_ON_FALSE(ret_flags & NBT_SERVER_PDC);
47 if (req_flags & DS_GC_SERVER_REQUIRED)
48 RETURN_ON_FALSE(ret_flags & NBT_SERVER_GC);
50 if (req_flags & DS_ONLY_LDAP_NEEDED)
51 RETURN_ON_FALSE(ret_flags & NBT_SERVER_LDAP);
53 if ((req_flags & DS_DIRECTORY_SERVICE_REQUIRED) ||
54 (req_flags & DS_DIRECTORY_SERVICE_PREFERRED))
55 RETURN_ON_FALSE(ret_flags & NBT_SERVER_DS);
57 if (req_flags & DS_KDC_REQUIRED)
58 RETURN_ON_FALSE(ret_flags & NBT_SERVER_KDC);
60 if (req_flags & DS_TIMESERV_REQUIRED)
61 RETURN_ON_FALSE(ret_flags & NBT_SERVER_TIMESERV);
63 if (req_flags & DS_WEB_SERVICE_REQUIRED)
64 RETURN_ON_FALSE(ret_flags & NBT_SERVER_ADS_WEB_SERVICE);
66 if (req_flags & DS_WRITABLE_REQUIRED)
67 RETURN_ON_FALSE(ret_flags & NBT_SERVER_WRITABLE);
69 if (req_flags & DS_DIRECTORY_SERVICE_6_REQUIRED)
70 RETURN_ON_FALSE(ret_flags &
71 (NBT_SERVER_SELECT_SECRET_DOMAIN_6 |
72 NBT_SERVER_FULL_SECRET_DOMAIN_6));
74 if (req_flags & DS_DIRECTORY_SERVICE_8_REQUIRED)
75 RETURN_ON_FALSE(ret_flags & NBT_SERVER_DS_8);
77 if (req_flags & DS_DIRECTORY_SERVICE_9_REQUIRED)
78 RETURN_ON_FALSE(ret_flags & NBT_SERVER_DS_9);
80 if (req_flags & DS_DIRECTORY_SERVICE_10_REQUIRED)
81 RETURN_ON_FALSE(ret_flags & NBT_SERVER_DS_10);
83 return true;
86 struct ldap_netlogon_state {
87 struct tevent_context *ev;
88 struct tsocket_address *local;
89 struct tsocket_address *remote;
90 enum client_netlogon_ping_protocol proto;
91 const char *filter;
93 struct tstream_context *plain;
94 struct tldap_context *tldap;
95 struct tstream_tls_params *tls_params;
97 struct netlogon_samlogon_response *response;
100 static void ldap_netlogon_connected(struct tevent_req *subreq);
101 static void ldap_netlogon_starttls_done(struct tevent_req *subreq);
102 static void ldap_netlogon_tls_set_up(struct tevent_req *subreq);
103 static void ldap_netlogon_search(struct tevent_req *req);
104 static void ldap_netlogon_searched(struct tevent_req *subreq);
106 static struct tevent_req *ldap_netlogon_send(
107 TALLOC_CTX *mem_ctx,
108 struct tevent_context *ev,
109 const struct tsocket_address *server,
110 enum client_netlogon_ping_protocol proto,
111 const char *filter)
113 struct tevent_req *req = NULL, *subreq = NULL;
114 struct ldap_netlogon_state *state = NULL;
115 uint16_t port;
116 int ret;
118 req = tevent_req_create(mem_ctx, &state, struct ldap_netlogon_state);
119 if (req == NULL) {
120 return NULL;
122 state->ev = ev;
123 state->filter = filter;
124 state->proto = proto;
126 state->remote = tsocket_address_copy(server, state);
127 if (tevent_req_nomem(state->remote, req)) {
128 return tevent_req_post(req, ev);
131 port = (proto == CLIENT_NETLOGON_PING_LDAPS) ? 636 : 389;
133 ret = tsocket_address_inet_set_port(state->remote, port);
134 if (ret != 0) {
135 tevent_req_nterror(req, map_nt_error_from_unix_common(errno));
136 return tevent_req_post(req, ev);
139 ret = tsocket_address_inet_from_strings(
140 state, "ip", NULL, 0, &state->local);
141 if (ret != 0) {
142 tevent_req_nterror(req, map_nt_error_from_unix_common(errno));
143 return tevent_req_post(req, ev);
146 subreq = tstream_inet_tcp_connect_send(state,
147 state->ev,
148 state->local,
149 state->remote);
150 if (tevent_req_nomem(subreq, req)) {
151 return tevent_req_post(req, ev);
153 tevent_req_set_callback(subreq, ldap_netlogon_connected, req);
155 return req;
158 static void ldap_netlogon_connected(struct tevent_req *subreq)
160 struct tevent_req *req = tevent_req_callback_data(subreq,
161 struct tevent_req);
162 struct ldap_netlogon_state *state = tevent_req_data(
163 req, struct ldap_netlogon_state);
164 int ret, err;
165 NTSTATUS status;
167 ret = tstream_inet_tcp_connect_recv(
168 subreq, &err, state, &state->plain, NULL);
169 TALLOC_FREE(subreq);
170 if (ret == -1) {
171 tevent_req_nterror(req, map_nt_error_from_unix_common(err));
172 return;
175 state->tldap = tldap_context_create_from_plain_stream(
176 state, &state->plain);
177 if (tevent_req_nomem(state->tldap, req)) {
178 return;
181 if (state->proto == CLIENT_NETLOGON_PING_LDAP) {
182 ldap_netlogon_search(req);
183 return;
186 status = tstream_tls_params_client(state,
187 false,
188 NULL,
189 NULL,
190 NULL,
191 "NORMAL",
192 TLS_VERIFY_PEER_NO_CHECK,
193 NULL,
194 &state->tls_params);
195 if (tevent_req_nterror(req, status)) {
196 DBG_ERR("tstream_tls_params_client(NO_CHECK): %s\n",
197 nt_errstr(status));
198 return;
201 if (state->proto == CLIENT_NETLOGON_PING_STARTTLS) {
202 subreq = tldap_extended_send(state,
203 state->ev,
204 state->tldap,
205 LDB_EXTENDED_START_TLS_OID,
206 NULL,
207 NULL,
209 NULL,
211 if (tevent_req_nomem(subreq, req)) {
212 return;
214 tevent_req_set_callback(subreq,
215 ldap_netlogon_starttls_done,
216 req);
217 return;
220 subreq = tldap_tls_connect_send(state,
221 state->ev,
222 state->tldap,
223 state->tls_params);
224 if (tevent_req_nomem(subreq, req)) {
225 return;
227 tevent_req_set_callback(subreq, ldap_netlogon_tls_set_up, req);
230 static void ldap_netlogon_starttls_done(struct tevent_req *subreq)
232 struct tevent_req *req = tevent_req_callback_data(subreq,
233 struct tevent_req);
234 struct ldap_netlogon_state *state = tevent_req_data(
235 req, struct ldap_netlogon_state);
236 TLDAPRC rc;
238 rc = tldap_extended_recv(subreq, NULL, NULL, NULL);
239 TALLOC_FREE(subreq);
240 if (!TLDAP_RC_IS_SUCCESS(rc)) {
241 tevent_req_nterror(req, NT_STATUS_LDAP(TLDAP_RC_V(rc)));
242 return;
245 subreq = tldap_tls_connect_send(state,
246 state->ev,
247 state->tldap,
248 state->tls_params);
249 if (tevent_req_nomem(subreq, req)) {
250 return;
252 tevent_req_set_callback(subreq, ldap_netlogon_tls_set_up, req);
255 static void ldap_netlogon_tls_set_up(struct tevent_req *subreq)
257 struct tevent_req *req = tevent_req_callback_data(subreq,
258 struct tevent_req);
259 TLDAPRC rc;
261 rc = tldap_tls_connect_recv(subreq);
262 TALLOC_FREE(subreq);
263 if (!TLDAP_RC_IS_SUCCESS(rc)) {
264 tevent_req_nterror(req, NT_STATUS_LDAP(TLDAP_RC_V(rc)));
265 return;
268 ldap_netlogon_search(req);
271 static void ldap_netlogon_search(struct tevent_req *req)
273 struct ldap_netlogon_state *state = tevent_req_data(
274 req, struct ldap_netlogon_state);
275 static const char *attrs[] = {"netlogon"};
276 struct tevent_req *subreq = NULL;
278 subreq = tldap_search_all_send(state,
279 state->ev,
280 state->tldap,
282 TLDAP_SCOPE_BASE,
283 state->filter,
284 attrs,
285 ARRAY_SIZE(attrs),
287 NULL,
289 NULL,
294 if (tevent_req_nomem(subreq, req)) {
295 return;
297 tevent_req_set_callback(subreq, ldap_netlogon_searched, req);
300 static void ldap_netlogon_searched(struct tevent_req *subreq)
302 struct tevent_req *req = tevent_req_callback_data(subreq,
303 struct tevent_req);
304 struct ldap_netlogon_state *state = tevent_req_data(
305 req, struct ldap_netlogon_state);
306 struct tldap_message **msgs = NULL;
307 DATA_BLOB blob = {.data = NULL};
308 NTSTATUS status;
309 TLDAPRC rc;
310 bool ok;
312 rc = tldap_search_all_recv(subreq, state, &msgs, NULL);
313 TALLOC_FREE(subreq);
314 if (!TLDAP_RC_IS_SUCCESS(rc)) {
315 tevent_req_nterror(req, NT_STATUS_LDAP(TLDAP_RC_V(rc)));
316 return;
319 if (talloc_array_length(msgs) != 1) {
320 tevent_req_nterror(req,
321 NT_STATUS_LDAP(TLDAP_RC_V(
322 TLDAP_NO_RESULTS_RETURNED)));
323 return;
326 ok = tldap_get_single_valueblob(msgs[0], "netlogon", &blob);
327 if (!ok) {
328 tevent_req_nterror(req,
329 NT_STATUS_LDAP(TLDAP_RC_V(
330 TLDAP_NO_RESULTS_RETURNED)));
331 return;
334 state->response = talloc(state, struct netlogon_samlogon_response);
335 if (tevent_req_nomem(state->response, req)) {
336 return;
339 status = pull_netlogon_samlogon_response(&blob,
340 state->response,
341 state->response);
342 if (!NT_STATUS_IS_OK(status)) {
343 tevent_req_nterror(req, status);
344 return;
347 tevent_req_done(req);
350 static NTSTATUS ldap_netlogon_recv(
351 struct tevent_req *req,
352 TALLOC_CTX *mem_ctx,
353 struct netlogon_samlogon_response **response)
355 struct ldap_netlogon_state *state = tevent_req_data(
356 req, struct ldap_netlogon_state);
357 NTSTATUS status;
359 if (tevent_req_is_nterror(req, &status)) {
360 return status;
362 *response = talloc_move(mem_ctx, &state->response);
363 tevent_req_received(req);
364 return NT_STATUS_OK;
367 struct cldap_netlogon_ping_state {
368 struct cldap_socket *sock;
369 struct cldap_search search;
370 struct netlogon_samlogon_response *response;
373 static void cldap_netlogon_ping_done(struct tevent_req *subreq);
375 static struct tevent_req *cldap_netlogon_ping_send(
376 TALLOC_CTX *mem_ctx,
377 struct tevent_context *ev,
378 const struct tsocket_address *server,
379 const char *filter)
381 struct tevent_req *req = NULL, *subreq = NULL;
382 struct cldap_netlogon_ping_state *state = NULL;
383 struct tsocket_address *server_389 = NULL;
384 static const char *const attr[] = {"NetLogon", NULL};
385 int ret;
386 NTSTATUS status;
388 req = tevent_req_create(mem_ctx,
389 &state,
390 struct cldap_netlogon_ping_state);
391 if (req == NULL) {
392 return NULL;
395 server_389 = tsocket_address_copy(server, state);
396 if (tevent_req_nomem(server_389, req)) {
397 return tevent_req_post(req, ev);
400 ret = tsocket_address_inet_set_port(server_389, 389);
401 if (ret != 0) {
402 tevent_req_nterror(req, map_nt_error_from_unix_common(errno));
403 return tevent_req_post(req, ev);
406 status = cldap_socket_init(state, NULL, server_389, &state->sock);
407 if (tevent_req_nterror(req, status)) {
408 return tevent_req_post(req, ev);
411 state->search = (struct cldap_search){
412 .in.filter = filter,
413 .in.attributes = attr,
414 .in.timeout = 2,
415 .in.retries = 2,
418 subreq = cldap_search_send(state, ev, state->sock, &state->search);
419 if (tevent_req_nomem(subreq, req)) {
420 return tevent_req_post(req, ev);
422 tevent_req_set_callback(subreq, cldap_netlogon_ping_done, req);
423 return req;
426 static void cldap_netlogon_ping_done(struct tevent_req *subreq)
428 struct tevent_req *req = tevent_req_callback_data(subreq,
429 struct tevent_req);
430 struct cldap_netlogon_ping_state *state = tevent_req_data(
431 req, struct cldap_netlogon_ping_state);
432 struct ldap_SearchResEntry *resp = NULL;
433 NTSTATUS status;
435 status = cldap_search_recv(subreq, state, &state->search);
436 TALLOC_FREE(subreq);
437 if (tevent_req_nterror(req, status)) {
438 return;
441 TALLOC_FREE(state->sock);
443 resp = state->search.out.response;
445 if (resp == NULL) {
446 tevent_req_nterror(req, NT_STATUS_NOT_FOUND);
447 return;
450 if (resp->num_attributes != 1 ||
451 !strequal(resp->attributes[0].name, "netlogon") ||
452 resp->attributes[0].num_values != 1 ||
453 resp->attributes[0].values->length < 2)
455 tevent_req_nterror(req, NT_STATUS_UNEXPECTED_NETWORK_ERROR);
456 return;
459 state->response = talloc(state, struct netlogon_samlogon_response);
460 if (tevent_req_nomem(state->response, req)) {
461 return;
464 status = pull_netlogon_samlogon_response(resp->attributes[0].values,
465 state->response,
466 state->response);
467 if (tevent_req_nterror(req, status)) {
468 return;
470 tevent_req_done(req);
473 static NTSTATUS cldap_netlogon_ping_recv(
474 struct tevent_req *req,
475 TALLOC_CTX *mem_ctx,
476 struct netlogon_samlogon_response **response)
478 struct cldap_netlogon_ping_state *state = tevent_req_data(
479 req, struct cldap_netlogon_ping_state);
480 NTSTATUS status;
482 if (tevent_req_is_nterror(req, &status)) {
483 return status;
485 *response = talloc_move(mem_ctx, &state->response);
486 tevent_req_received(req);
487 return NT_STATUS_OK;
490 struct netlogon_ping_state {
491 struct netlogon_samlogon_response *response;
494 static void netlogon_ping_done_cldap(struct tevent_req *subreq);
495 static void netlogon_ping_done_ldaps(struct tevent_req *subreq);
497 static struct tevent_req *netlogon_ping_send(
498 TALLOC_CTX *mem_ctx,
499 struct tevent_context *ev,
500 struct tsocket_address *server,
501 enum client_netlogon_ping_protocol proto,
502 const char *filter,
503 struct timeval timeout)
505 struct tevent_req *req = NULL, *subreq = NULL;
506 struct netlogon_ping_state *state = NULL;
508 req = tevent_req_create(mem_ctx, &state, struct netlogon_ping_state);
509 if (req == NULL) {
510 return NULL;
513 switch (proto) {
514 case CLIENT_NETLOGON_PING_CLDAP:
515 subreq = cldap_netlogon_ping_send(state, ev, server, filter);
516 if (tevent_req_nomem(subreq, req)) {
517 return tevent_req_post(req, ev);
519 tevent_req_set_callback(subreq, netlogon_ping_done_cldap, req);
520 break;
521 case CLIENT_NETLOGON_PING_LDAP:
522 case CLIENT_NETLOGON_PING_LDAPS:
523 case CLIENT_NETLOGON_PING_STARTTLS:
524 subreq = ldap_netlogon_send(state, ev, server, proto, filter);
525 if (tevent_req_nomem(subreq, req)) {
526 return tevent_req_post(req, ev);
528 tevent_req_set_callback(subreq, netlogon_ping_done_ldaps, req);
529 break;
530 default:
531 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
532 return tevent_req_post(req, ev);
533 break;
536 return req;
539 static void netlogon_ping_done_cldap(struct tevent_req *subreq)
541 struct tevent_req *req = tevent_req_callback_data(subreq,
542 struct tevent_req);
543 struct netlogon_ping_state *state = tevent_req_data(
544 req, struct netlogon_ping_state);
545 NTSTATUS status;
547 status = cldap_netlogon_ping_recv(subreq, state, &state->response);
548 if (tevent_req_nterror(req, status)) {
549 return;
551 tevent_req_done(req);
554 static void netlogon_ping_done_ldaps(struct tevent_req *subreq)
556 struct tevent_req *req = tevent_req_callback_data(subreq,
557 struct tevent_req);
558 struct netlogon_ping_state *state = tevent_req_data(
559 req, struct netlogon_ping_state);
560 NTSTATUS status;
562 status = ldap_netlogon_recv(subreq, state, &state->response);
563 TALLOC_FREE(subreq);
564 if (tevent_req_nterror(req, status)) {
565 return;
567 tevent_req_done(req);
570 static NTSTATUS netlogon_ping_recv(
571 struct tevent_req *req,
572 TALLOC_CTX *mem_ctx,
573 struct netlogon_samlogon_response **response)
575 struct netlogon_ping_state *state = tevent_req_data(
576 req, struct netlogon_ping_state);
577 NTSTATUS status;
579 if (tevent_req_is_nterror(req, &status)) {
580 return status;
582 *response = talloc_move(mem_ctx, &state->response);
583 return NT_STATUS_OK;
586 struct netlogon_pings_state {
587 struct tevent_context *ev;
589 struct tsocket_address **servers;
590 size_t num_servers;
591 size_t min_servers;
592 struct timeval timeout;
593 enum client_netlogon_ping_protocol proto;
594 uint32_t required_flags;
596 char *filter;
597 size_t num_sent;
598 size_t num_received;
599 size_t num_good_received;
600 struct tevent_req **reqs;
601 struct netlogon_samlogon_response **responses;
604 static void netlogon_pings_next(struct tevent_req *subreq);
605 static void netlogon_pings_done(struct tevent_req *subreq);
607 struct tevent_req *netlogon_pings_send(TALLOC_CTX *mem_ctx,
608 struct tevent_context *ev,
609 enum client_netlogon_ping_protocol proto,
610 struct tsocket_address **servers,
611 size_t num_servers,
612 struct netlogon_ping_filter filter,
613 size_t min_servers,
614 struct timeval timeout)
616 struct tevent_req *req = NULL;
617 struct netlogon_pings_state *state = NULL;
618 char *filter_str = NULL;
619 size_t i;
621 req = tevent_req_create(mem_ctx, &state, struct netlogon_pings_state);
622 if (req == NULL) {
623 return NULL;
625 state->ev = ev;
626 state->proto = proto;
627 state->servers = servers;
628 state->num_servers = num_servers;
629 state->min_servers = min_servers;
630 state->timeout = timeout;
631 state->required_flags = filter.required_flags;
633 state->reqs = talloc_zero_array(state,
634 struct tevent_req *,
635 num_servers);
636 if (tevent_req_nomem(state->reqs, req)) {
637 return tevent_req_post(req, ev);
640 state->responses = talloc_zero_array(
641 state, struct netlogon_samlogon_response *, num_servers);
642 if (tevent_req_nomem(state->responses, req)) {
643 return tevent_req_post(req, ev);
646 filter_str = talloc_asprintf(state,
647 "(&(NtVer=%s)",
648 ldap_encode_ndr_uint32(state,
649 filter.ntversion));
650 if (filter.domain != NULL) {
651 talloc_asprintf_addbuf(&filter_str,
652 "(DnsDomain=%s)",
653 filter.domain);
655 if (filter.acct_ctrl != -1) {
656 talloc_asprintf_addbuf(
657 &filter_str,
658 "(AAC=%s)",
659 ldap_encode_ndr_uint32(mem_ctx, filter.acct_ctrl));
661 if (filter.domain_sid != NULL) {
662 talloc_asprintf_addbuf(
663 &filter_str,
664 "(domainSid=%s)",
665 ldap_encode_ndr_dom_sid(mem_ctx, filter.domain_sid));
667 if (filter.domain_guid != NULL) {
668 talloc_asprintf_addbuf(
669 &filter_str,
670 "(DomainGuid=%s)",
671 ldap_encode_ndr_GUID(mem_ctx, filter.domain_guid));
673 if (filter.hostname != NULL) {
674 talloc_asprintf_addbuf(&filter_str,
675 "(Host=%s)",
676 filter.hostname);
678 if (filter.user != NULL) {
679 talloc_asprintf_addbuf(&filter_str, "(User=%s)", filter.user);
681 talloc_asprintf_addbuf(&filter_str, ")");
683 if (tevent_req_nomem(filter_str, req)) {
684 return tevent_req_post(req, ev);
686 state->filter = filter_str;
688 for (i = 0; i < min_servers; i++) {
689 state->reqs[i] = netlogon_ping_send(state->reqs,
690 state->ev,
691 state->servers[i],
692 state->proto,
693 state->filter,
694 state->timeout);
695 if (tevent_req_nomem(state->reqs[i], req)) {
696 return tevent_req_post(req, ev);
698 tevent_req_set_callback(state->reqs[i],
699 netlogon_pings_done,
700 req);
702 state->num_sent = min_servers;
703 if (state->num_sent < state->num_servers) {
705 * After 100 milliseconds fire the next one
707 struct tevent_req *subreq = tevent_wakeup_send(
708 state, state->ev, timeval_current_ofs(0, 100000));
709 if (tevent_req_nomem(subreq, req)) {
710 return tevent_req_post(req, ev);
712 tevent_req_set_callback(subreq, netlogon_pings_next, req);
715 return req;
718 static void netlogon_pings_next(struct tevent_req *subreq)
720 struct tevent_req *req = tevent_req_callback_data(subreq,
721 struct tevent_req);
722 struct netlogon_pings_state *state = tevent_req_data(
723 req, struct netlogon_pings_state);
724 bool ret;
726 ret = tevent_wakeup_recv(subreq);
727 TALLOC_FREE(subreq);
728 if (!ret) {
729 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
730 return;
733 subreq = netlogon_ping_send(state->reqs,
734 state->ev,
735 state->servers[state->num_sent],
736 state->proto,
737 state->filter,
738 state->timeout);
739 if (tevent_req_nomem(subreq, req)) {
740 return;
742 tevent_req_set_callback(subreq, netlogon_pings_done, req);
743 state->reqs[state->num_sent] = subreq;
744 state->num_sent += 1;
746 if (state->num_sent < state->num_servers) {
748 * After 100 milliseconds fire the next one
750 subreq = tevent_wakeup_send(state,
751 state->ev,
752 timeval_current_ofs(0, 100000));
753 if (tevent_req_nomem(subreq, req)) {
754 return;
756 tevent_req_set_callback(subreq, netlogon_pings_next, req);
760 static void netlogon_pings_done(struct tevent_req *subreq)
762 struct tevent_req *req = tevent_req_callback_data(subreq,
763 struct tevent_req);
764 struct netlogon_pings_state *state = tevent_req_data(
765 req, struct netlogon_pings_state);
766 struct netlogon_samlogon_response *response = NULL;
767 NTSTATUS status;
768 size_t i;
770 for (i = 0; i < state->num_sent; i++) {
771 if (state->reqs[i] == subreq) {
772 break;
776 if (i == state->num_sent) {
778 * Got a response we did not fire...
780 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
781 return;
783 state->reqs[i] = NULL;
785 status = netlogon_ping_recv(subreq, state, &response);
786 TALLOC_FREE(subreq);
787 state->num_received += 1;
789 if (NT_STATUS_IS_OK(status)) {
790 uint32_t ret_flags;
791 bool ok;
793 switch (response->ntver) {
794 case NETLOGON_NT_VERSION_5EX:
795 ret_flags = response->data.nt5_ex.server_type;
796 break;
797 case NETLOGON_NT_VERSION_5:
798 ret_flags = response->data.nt5.server_type;
799 break;
800 default:
801 ret_flags = 0;
802 break;
805 ok = check_cldap_reply_required_flags(ret_flags,
806 state->required_flags);
807 if (ok) {
808 state->responses[i] = talloc_move(state->responses,
809 &response);
810 state->num_good_received += 1;
814 if (state->num_good_received >= state->min_servers) {
815 tevent_req_done(req);
816 return;
818 if (state->num_received == state->num_servers) {
820 * Everybody replied, but we did not get enough good
821 * answers (see above)
823 tevent_req_nterror(req, NT_STATUS_NOT_FOUND);
824 return;
827 * Wait for more answers
831 NTSTATUS netlogon_pings_recv(struct tevent_req *req,
832 TALLOC_CTX *mem_ctx,
833 struct netlogon_samlogon_response ***responses)
835 struct netlogon_pings_state *state = tevent_req_data(
836 req, struct netlogon_pings_state);
837 NTSTATUS status;
839 if (tevent_req_is_nterror(req, &status)) {
840 return status;
842 *responses = talloc_move(mem_ctx, &state->responses);
843 tevent_req_received(req);
844 return NT_STATUS_OK;
847 NTSTATUS netlogon_pings(TALLOC_CTX *mem_ctx,
848 enum client_netlogon_ping_protocol proto,
849 struct tsocket_address **servers,
850 int num_servers,
851 struct netlogon_ping_filter filter,
852 int min_servers,
853 struct timeval timeout,
854 struct netlogon_samlogon_response ***responses)
856 TALLOC_CTX *frame = talloc_stackframe();
857 struct tevent_context *ev = NULL;
858 struct tevent_req *req = NULL;
859 NTSTATUS status = NT_STATUS_NO_MEMORY;
861 ev = samba_tevent_context_init(frame);
862 if (ev == NULL) {
863 goto fail;
865 req = netlogon_pings_send(frame,
867 proto,
868 servers,
869 num_servers,
870 filter,
871 min_servers,
872 timeout);
873 if (req == NULL) {
874 goto fail;
876 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
877 goto fail;
879 status = netlogon_pings_recv(req, mem_ctx, responses);
880 fail:
881 TALLOC_FREE(frame);
882 return status;