#include "libads/cldap.h"
#include "libads/netlogon_ping.h"
-struct cldap_multi_netlogon_state {
- struct tevent_context *ev;
- const struct tsocket_address * const *servers;
- int num_servers;
- const char *domain;
- const char *hostname;
- unsigned ntversion;
- int min_servers;
-
- struct cldap_socket **cldap;
- struct tevent_req **subreqs;
- int num_sent;
- int num_received;
- int num_good_received;
- struct cldap_netlogon *ios;
- struct netlogon_samlogon_response **responses;
-};
-
-static void cldap_multi_netlogon_done(struct tevent_req *subreq);
-static void cldap_multi_netlogon_next(struct tevent_req *subreq);
-
/****************************************************************
****************************************************************/
return true;
}
-/*
- * Do a parallel cldap ping to the servers. The first "min_servers"
- * are fired directly, the remaining ones in 100msec intervals. If
- * "min_servers" responses came in successfully, we immediately reply,
- * not waiting for the remaining ones.
- */
-
-struct tevent_req *cldap_multi_netlogon_send(
- TALLOC_CTX *mem_ctx, struct tevent_context *ev,
- const struct tsocket_address * const *servers, int num_servers,
- const char *domain, const char *hostname, unsigned ntversion,
- int min_servers)
-{
- struct tevent_req *req, *subreq;
- struct cldap_multi_netlogon_state *state;
- int i;
-
- req = tevent_req_create(mem_ctx, &state,
- struct cldap_multi_netlogon_state);
- if (req == NULL) {
- return NULL;
- }
- state->ev = ev;
- state->servers = servers;
- state->num_servers = num_servers;
- state->domain = domain;
- state->hostname = hostname;
- state->ntversion = ntversion;
- state->min_servers = min_servers;
-
- if (min_servers > num_servers) {
- tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
- return tevent_req_post(req, ev);
- }
-
- state->subreqs = talloc_zero_array(state,
- struct tevent_req *,
- num_servers);
- if (tevent_req_nomem(state->subreqs, req)) {
- return tevent_req_post(req, ev);
- }
-
- state->cldap = talloc_zero_array(state,
- struct cldap_socket *,
- num_servers);
- if (tevent_req_nomem(state->cldap, req)) {
- return tevent_req_post(req, ev);
- }
-
- state->responses = talloc_zero_array(state,
- struct netlogon_samlogon_response *,
- num_servers);
- if (tevent_req_nomem(state->responses, req)) {
- return tevent_req_post(req, ev);
- }
-
- state->ios = talloc_array(state->responses,
- struct cldap_netlogon,
- num_servers);
- if (tevent_req_nomem(state->ios, req)) {
- return tevent_req_post(req, ev);
- }
-
- for (i=0; i<num_servers; i++) {
- NTSTATUS status;
-
- status = cldap_socket_init(state->cldap,
- NULL, /* local_addr */
- state->servers[i],
- &state->cldap[i]);
- if (!NT_STATUS_IS_OK(status)) {
- /*
- * Don't error out all sends just
- * because one cldap_socket_init() failed.
- * Log it here, and the cldap_netlogon_send()
- * will catch it (with in.dest_address == NULL)
- * and correctly error out in
- * cldap_multi_netlogon_done(). This still allows
- * the other requests to be concurrently sent.
- */
- DBG_NOTICE("cldap_socket_init failed for %s "
- " error %s\n",
- tsocket_address_string(state->servers[i],
- req),
- nt_errstr(status));
- }
-
- state->ios[i] = (struct cldap_netlogon){
- .in.realm = domain, .in.version = ntversion};
- }
-
- for (i=0; i<min_servers; i++) {
- state->subreqs[i] = cldap_netlogon_send(state->subreqs,
- state->ev,
- state->cldap[i],
- &state->ios[i]);
- if (tevent_req_nomem(state->subreqs[i], req)) {
- return tevent_req_post(req, ev);
- }
- tevent_req_set_callback(
- state->subreqs[i], cldap_multi_netlogon_done, req);
- }
- state->num_sent = min_servers;
-
- if (state->num_sent < state->num_servers) {
- /*
- * After 100 milliseconds fire the next one
- */
- subreq = tevent_wakeup_send(state, state->ev,
- timeval_current_ofs(0, 100000));
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
- }
- tevent_req_set_callback(subreq, cldap_multi_netlogon_next,
- req);
- }
-
- return req;
-}
-
-static void cldap_multi_netlogon_done(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct cldap_multi_netlogon_state *state = tevent_req_data(
- req, struct cldap_multi_netlogon_state);
- NTSTATUS status;
- struct netlogon_samlogon_response *response = NULL;
- int i;
-
- for (i=0; i<state->num_sent; i++) {
- if (state->subreqs[i] == subreq) {
- break;
- }
- }
- if (i == state->num_sent) {
- /*
- * Got a response we did not fire...
- */
- tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
- return;
- }
- state->subreqs[i] = NULL;
-
- response = talloc_zero(state, struct netlogon_samlogon_response);
- if (tevent_req_nomem(response, req)) {
- return;
- }
-
- status = cldap_netlogon_recv(subreq, response,
- &state->ios[i]);
- TALLOC_FREE(subreq);
- state->num_received += 1;
-
- if (NT_STATUS_IS_OK(status)) {
- *response = *state->ios[i].out.netlogon;
- state->responses[i] = talloc_move(state->responses,
- &response);
- state->num_good_received += 1;
- }
-
- if ((state->num_received == state->num_servers) ||
- (state->num_good_received >= state->min_servers)) {
- tevent_req_done(req);
- return;
- }
-}
-
-static void cldap_multi_netlogon_next(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- struct cldap_multi_netlogon_state *state = tevent_req_data(
- req, struct cldap_multi_netlogon_state);
- bool ret;
-
- ret = tevent_wakeup_recv(subreq);
- TALLOC_FREE(subreq);
- if (!ret) {
- tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
- return;
- }
-
- subreq = cldap_netlogon_send(state->subreqs,
- state->ev,
- state->cldap[state->num_sent],
- &state->ios[state->num_sent]);
- if (tevent_req_nomem(subreq, req)) {
- return;
- }
- tevent_req_set_callback(subreq, cldap_multi_netlogon_done, req);
- state->subreqs[state->num_sent] = subreq;
- state->num_sent += 1;
-
- if (state->num_sent < state->num_servers) {
- /*
- * After 100 milliseconds fire the next one
- */
- subreq = tevent_wakeup_send(state, state->ev,
- timeval_current_ofs(0, 100000));
- if (tevent_req_nomem(subreq, req)) {
- return;
- }
- tevent_req_set_callback(subreq, cldap_multi_netlogon_next,
- req);
- }
-}
-
-NTSTATUS cldap_multi_netlogon_recv(
- struct tevent_req *req, TALLOC_CTX *mem_ctx,
- struct netlogon_samlogon_response ***responses)
-{
- struct cldap_multi_netlogon_state *state = tevent_req_data(
- req, struct cldap_multi_netlogon_state);
- NTSTATUS status;
-
- if (tevent_req_is_nterror(req, &status) &&
- !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
- return status;
- }
- /*
- * If we timeout, give back what we have so far
- */
- *responses = talloc_move(mem_ctx, &state->responses);
- return NT_STATUS_OK;
-}
-
-NTSTATUS cldap_multi_netlogon(
- TALLOC_CTX *mem_ctx,
- const struct tsocket_address * const *servers,
- int num_servers,
- const char *domain, const char *hostname, unsigned ntversion,
- int min_servers, struct timeval timeout,
- struct netlogon_samlogon_response ***responses)
-{
- struct tevent_context *ev;
- struct tevent_req *req;
- NTSTATUS status = NT_STATUS_NO_MEMORY;
-
- ev = samba_tevent_context_init(talloc_tos());
- if (ev == NULL) {
- goto fail;
- }
- req = cldap_multi_netlogon_send(
- ev, ev, servers, num_servers, domain, hostname, ntversion,
- min_servers);
- if (req == NULL) {
- goto fail;
- }
- if (!tevent_req_set_endtime(req, ev, timeout)) {
- goto fail;
- }
- if (!tevent_req_poll_ntstatus(req, ev, &status)) {
- goto fail;
- }
- status = cldap_multi_netlogon_recv(req, mem_ctx, responses);
-fail:
- TALLOC_FREE(ev);
- return status;
-}
-
/*******************************************************************
do a cldap netlogon query. Always 389/udp
*******************************************************************/