fail_over_srv.c revision 4e748c28dec6fcb732ebe24829f1b750074d488e
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen/*
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen Authors:
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen Pavel B??ezina <pbrezina@redhat.com>
50e4970035d1278597d13cac6c5ae26e7af93025Timo Sirainen
50e4970035d1278597d13cac6c5ae26e7af93025Timo Sirainen Copyright (C) 2013 Red Hat
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi
14102a0c5db8828ca8c7751ec96587fadc97a0bcTimo Sirainen This program is free software; you can redistribute it and/or modify
14102a0c5db8828ca8c7751ec96587fadc97a0bcTimo Sirainen it under the terms of the GNU General Public License as published by
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi the Free Software Foundation; either version 3 of the License, or
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi (at your option) any later version.
aaa1b6bb4cd2d7f8f4e7977d61176ea1c8f7e32bAki Tuomi
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi This program is distributed in the hope that it will be useful,
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi but WITHOUT ANY WARRANTY; without even the implied warranty of
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen GNU General Public License for more details.
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi
05128fda80748e107bccdece0a3d23551e99e8f3Timo Sirainen You should have received a copy of the GNU General Public License
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi along with this program. If not, see <http://www.gnu.org/licenses/>.
79ec87ea6861e2dd447f69ab44a7cc4e4fce3fddAki Tuomi*/
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi#include <strings.h>
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi#include <talloc.h>
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi#include <tevent.h>
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi#include "util/util.h"
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi#include "resolv/async_resolv.h"
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi#include "providers/fail_over_srv.h"
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomistruct fo_discover_srv_state {
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi char *dns_domain;
3fd8086f71f25a68e33993e24123b10b671dac67Aki Tuomi struct fo_server_info *servers;
3fd8086f71f25a68e33993e24123b10b671dac67Aki Tuomi size_t num_servers;
bd13998cde153abdb189593ad4229bf73bc2dd34Aki Tuomi};
bd13998cde153abdb189593ad4229bf73bc2dd34Aki Tuomi
3fd8086f71f25a68e33993e24123b10b671dac67Aki Tuomistatic void fo_discover_srv_done(struct tevent_req *subreq);
3fd8086f71f25a68e33993e24123b10b671dac67Aki Tuomi
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomistruct tevent_req *fo_discover_srv_send(TALLOC_CTX *mem_ctx,
14102a0c5db8828ca8c7751ec96587fadc97a0bcTimo Sirainen struct tevent_context *ev,
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi struct resolv_ctx *resolv_ctx,
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi const char *service,
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi const char *protocol,
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi const char **discovery_domains)
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi{
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi struct fo_discover_srv_state *state = NULL;
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi struct tevent_req *req = NULL;
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi struct tevent_req *subreq = NULL;
79ec87ea6861e2dd447f69ab44a7cc4e4fce3fddAki Tuomi errno_t ret;
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi req = tevent_req_create(mem_ctx, &state, struct fo_discover_srv_state);
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi if (req == NULL) {
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n"));
1e11a94ec50fc9b57eb2c859771c6a326ccaf86fAki Tuomi return NULL;
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi }
aaa1b6bb4cd2d7f8f4e7977d61176ea1c8f7e32bAki Tuomi
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi subreq = resolv_discover_srv_send(state, ev, resolv_ctx, service,
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen protocol, discovery_domains);
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen if (subreq == NULL) {
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen ret = ENOMEM;
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen goto immediately;
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen }
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi tevent_req_set_callback(subreq, fo_discover_srv_done, req);
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi return req;
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomiimmediately:
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi tevent_req_error(req, ret);
3fd8086f71f25a68e33993e24123b10b671dac67Aki Tuomi tevent_req_post(req, ev);
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi return req;
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi}
aaa1b6bb4cd2d7f8f4e7977d61176ea1c8f7e32bAki Tuomi
aaa1b6bb4cd2d7f8f4e7977d61176ea1c8f7e32bAki Tuomistatic void fo_discover_srv_done(struct tevent_req *subreq)
aaa1b6bb4cd2d7f8f4e7977d61176ea1c8f7e32bAki Tuomi{
79bbb900ffba886779474dfb04c41408f0ba0602Timo Sirainen struct fo_discover_srv_state *state = NULL;
2029c2cb37d7308e74329c9a15b6cf07a3468314Timo Sirainen struct tevent_req *req = NULL;
50e4970035d1278597d13cac6c5ae26e7af93025Timo Sirainen struct ares_srv_reply *reply_list = NULL;
50e4970035d1278597d13cac6c5ae26e7af93025Timo Sirainen struct ares_srv_reply *record = NULL;
aaa1b6bb4cd2d7f8f4e7977d61176ea1c8f7e32bAki Tuomi int i;
50e4970035d1278597d13cac6c5ae26e7af93025Timo Sirainen errno_t ret;
50e4970035d1278597d13cac6c5ae26e7af93025Timo Sirainen
79bbb900ffba886779474dfb04c41408f0ba0602Timo Sirainen req = tevent_req_callback_data(subreq, struct tevent_req);
79bbb900ffba886779474dfb04c41408f0ba0602Timo Sirainen state = tevent_req_data(req, struct fo_discover_srv_state);
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen ret = resolv_discover_srv_recv(state, subreq,
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen &reply_list, &state->dns_domain);
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi talloc_zfree(subreq);
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi if (ret == ENOENT) {
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi ret = ERR_SRV_NOT_FOUND;
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen goto done;
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen } else if (ret == EIO) {
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen ret = ERR_SRV_LOOKUP_ERROR;
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen goto done;
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen } else if (ret != EOK) {
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen goto done;
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen }
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen DEBUG(SSSDBG_TRACE_FUNC, ("Got answer. Processing...\n"));
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen
36a052b7bd94ccb47abbb6b15c1380f03780ba20Timo Sirainen /* sort and store the answer */
36a052b7bd94ccb47abbb6b15c1380f03780ba20Timo Sirainen ret = resolv_sort_srv_reply(state, &reply_list);
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen if (ret != EOK) {
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, ("Could not sort the answers from DNS "
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen "[%d]: %s\n", ret, strerror(ret)));
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen goto done;
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen }
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen state->num_servers = 0;
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen for (record = reply_list; record != NULL; record = record->next) {
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen state->num_servers++;
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen }
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen DEBUG(SSSDBG_TRACE_FUNC, ("Got %lu servers\n", state->num_servers));
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen state->servers = talloc_array(state, struct fo_server_info,
aaa1b6bb4cd2d7f8f4e7977d61176ea1c8f7e32bAki Tuomi state->num_servers);
aaa1b6bb4cd2d7f8f4e7977d61176ea1c8f7e32bAki Tuomi if (state->servers == NULL) {
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi ret = ENOMEM;
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi goto done;
7d500ecf27acc5b65615ee9e72d6da6bacf799d2Timo Sirainen }
6a8c95b0693c93601e948e06bfe1f89abdd43307Timo Sirainen
6a8c95b0693c93601e948e06bfe1f89abdd43307Timo Sirainen for (record = reply_list, i = 0;
7a8ef11587fd50d5888223fc3d91911775a21ba5Aki Tuomi record != NULL;
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi record = record->next, i++) {
79bbb900ffba886779474dfb04c41408f0ba0602Timo Sirainen state->servers[i].host = talloc_steal(state->servers, record->host);
36a052b7bd94ccb47abbb6b15c1380f03780ba20Timo Sirainen state->servers[i].port = record->port;
aaa1b6bb4cd2d7f8f4e7977d61176ea1c8f7e32bAki Tuomi }
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi
36a052b7bd94ccb47abbb6b15c1380f03780ba20Timo Sirainen talloc_zfree(reply_list);
aaa1b6bb4cd2d7f8f4e7977d61176ea1c8f7e32bAki Tuomi
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi ret = EOK;
aaa1b6bb4cd2d7f8f4e7977d61176ea1c8f7e32bAki Tuomi
db8b229230860a6c12daa0017a49396986368897Aki Tuomidone:
aaa1b6bb4cd2d7f8f4e7977d61176ea1c8f7e32bAki Tuomi if (ret != EOK) {
db8b229230860a6c12daa0017a49396986368897Aki Tuomi tevent_req_error(req, ret);
aaa1b6bb4cd2d7f8f4e7977d61176ea1c8f7e32bAki Tuomi return;
db8b229230860a6c12daa0017a49396986368897Aki Tuomi }
aaa1b6bb4cd2d7f8f4e7977d61176ea1c8f7e32bAki Tuomi
db8b229230860a6c12daa0017a49396986368897Aki Tuomi tevent_req_done(req);
aaa1b6bb4cd2d7f8f4e7977d61176ea1c8f7e32bAki Tuomi}
4afc67eb96f8d6b7dc94d63d3c7fe4f556c4fceeTimo Sirainen
aaa1b6bb4cd2d7f8f4e7977d61176ea1c8f7e32bAki Tuomierrno_t fo_discover_srv_recv(TALLOC_CTX *mem_ctx,
db8b229230860a6c12daa0017a49396986368897Aki Tuomi struct tevent_req *req,
14af7be4aa26d55c341cd6efe32bb2add2c39830Aki Tuomi char **_dns_domain,
1e8a6a8708b612eee65f83ef6874aab94b15eb50Timo Sirainen struct fo_server_info **_servers,
2029c2cb37d7308e74329c9a15b6cf07a3468314Timo Sirainen size_t *_num_servers)
1e8a6a8708b612eee65f83ef6874aab94b15eb50Timo Sirainen{
68cc278710182485b6c09e9a9ff8db90a727f343Aki Tuomi struct fo_discover_srv_state *state = NULL;
68cc278710182485b6c09e9a9ff8db90a727f343Aki Tuomi state = tevent_req_data(req, struct fo_discover_srv_state);
676d5601a8e087b25eb4dd5509079ab832e66831Aki Tuomi
676d5601a8e087b25eb4dd5509079ab832e66831Aki Tuomi TEVENT_REQ_RETURN_ON_ERROR(req);
676d5601a8e087b25eb4dd5509079ab832e66831Aki Tuomi
7616a1520f0d8ee5cc96f6b044c7fde1a9f9798cAki Tuomi if (_dns_domain != NULL) {
6eb1a7a7ae2c1dfff6731956ade08f9a4a7c791aAki Tuomi *_dns_domain = talloc_steal(mem_ctx, state->dns_domain);
99819adc9638200bc2ec1b68da9d2c68e8435740Aki Tuomi }
68cc278710182485b6c09e9a9ff8db90a727f343Aki Tuomi
55accf49e32ff93bfdd92961cb54ccc8c329147cTimo Sirainen if (_servers != NULL) {
*_servers = talloc_steal(mem_ctx, state->servers);
}
if (_num_servers != NULL) {
*_num_servers = state->num_servers;
}
return EOK;
}
struct fo_discover_servers_state {
struct tevent_context *ev;
struct resolv_ctx *resolv_ctx;
const char *service;
const char *protocol;
const char *primary_domain;
const char *backup_domain;
char *dns_domain;
struct fo_server_info *primary_servers;
size_t num_primary_servers;
struct fo_server_info *backup_servers;
size_t num_backup_servers;
};
static void fo_discover_servers_primary_done(struct tevent_req *subreq);
static void fo_discover_servers_backup_done(struct tevent_req *subreq);
struct tevent_req *fo_discover_servers_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct resolv_ctx *resolv_ctx,
const char *service,
const char *protocol,
const char *primary_domain,
const char *backup_domain)
{
struct fo_discover_servers_state *state = NULL;
struct tevent_req *req = NULL;
struct tevent_req *subreq = NULL;
const char **domains = NULL;
errno_t ret;
req = tevent_req_create(mem_ctx, &state,
struct fo_discover_servers_state);
if (req == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n"));
return NULL;
}
if (primary_domain == NULL) {
if (backup_domain == NULL) {
state->primary_servers = NULL;
state->num_primary_servers = 0;
state->backup_servers = NULL;
state->num_backup_servers = 0;
state->dns_domain = NULL;
ret = EOK;
goto immediately;
} else {
primary_domain = backup_domain;
backup_domain = NULL;
}
}
state->ev = ev;
state->resolv_ctx = resolv_ctx;
state->service = talloc_strdup(state, service);
if (state->service == NULL) {
ret = ENOMEM;
goto immediately;
}
state->protocol = talloc_strdup(state, protocol);
if (state->protocol == NULL) {
ret = ENOMEM;
goto immediately;
}
state->primary_domain = talloc_strdup(state, primary_domain);
if (state->primary_domain == NULL) {
ret = ENOMEM;
goto immediately;
}
state->backup_domain = talloc_strdup(state, backup_domain);
if (state->backup_domain == NULL && backup_domain != NULL) {
ret = ENOMEM;
goto immediately;
}
DEBUG(SSSDBG_TRACE_FUNC, ("Looking up primary servers\n"));
domains = talloc_zero_array(state, const char *, 3);
if (domains == NULL) {
ret = ENOMEM;
goto immediately;
}
domains[0] = state->primary_domain;
domains[1] = state->backup_domain;
subreq = fo_discover_srv_send(state, ev, resolv_ctx,
state->service, state->protocol, domains);
if (subreq == NULL) {
ret = ENOMEM;
goto immediately;
}
tevent_req_set_callback(subreq, fo_discover_servers_primary_done, req);
return req;
immediately:
tevent_req_error(req, ret);
tevent_req_post(req, ev);
return req;
}
static void fo_discover_servers_primary_done(struct tevent_req *subreq)
{
struct fo_discover_servers_state *state = NULL;
struct tevent_req *req = NULL;
const char **domains = NULL;
errno_t ret;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct fo_discover_servers_state);
ret = fo_discover_srv_recv(state, subreq,
&state->dns_domain,
&state->primary_servers,
&state->num_primary_servers);
talloc_zfree(subreq);
if (ret != EOK) {
goto done;
}
if (strcasecmp(state->dns_domain, state->backup_domain) == 0) {
/* primary domain was unreachable, we will use servers from backup
* domain as primary */
state->backup_servers = NULL;
state->num_backup_servers = 0;
ret = EOK;
goto done;
}
DEBUG(SSSDBG_TRACE_FUNC, ("Looking up backup servers\n"));
domains = talloc_zero_array(state, const char *, 2);
if (domains == NULL) {
ret = ENOMEM;
goto done;
}
domains[0] = state->backup_domain;
subreq = fo_discover_srv_send(state, state->ev, state->resolv_ctx,
state->service, state->protocol, domains);
if (subreq == NULL) {
ret = ENOMEM;
goto done;
}
tevent_req_set_callback(subreq, fo_discover_servers_backup_done, req);
ret = EAGAIN;
done:
if (ret == EOK) {
tevent_req_done(req);
} else if (ret != EAGAIN) {
tevent_req_error(req, ret);
}
return;
}
static void fo_discover_servers_backup_done(struct tevent_req *subreq)
{
struct fo_discover_servers_state *state = NULL;
struct tevent_req *req = NULL;
errno_t ret;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct fo_discover_servers_state);
ret = fo_discover_srv_recv(state, subreq, NULL,
&state->backup_servers,
&state->num_backup_servers);
talloc_zfree(subreq);
if (ret == ERR_SRV_NOT_FOUND || ret == ERR_SRV_LOOKUP_ERROR) {
/* we have successfully fetched primary servers, so we will
* finish the request normally */
DEBUG(SSSDBG_MINOR_FAILURE, ("Unable to retrieve backup servers "
"[%d]: %s\n", ret, sss_strerror(ret)));
ret = EOK;
}
if (ret != EOK) {
tevent_req_error(req, ret);
return;
}
tevent_req_done(req);
}
errno_t fo_discover_servers_recv(TALLOC_CTX *mem_ctx,
struct tevent_req *req,
char **_dns_domain,
struct fo_server_info **_primary_servers,
size_t *_num_primary_servers,
struct fo_server_info **_backup_servers,
size_t *_num_backup_servers)
{
struct fo_discover_servers_state *state = NULL;
state = tevent_req_data(req, struct fo_discover_servers_state);
TEVENT_REQ_RETURN_ON_ERROR(req);
if (_primary_servers) {
*_primary_servers = talloc_steal(mem_ctx, state->primary_servers);
}
if (_num_primary_servers) {
*_num_primary_servers = state->num_primary_servers;
}
if (_backup_servers) {
*_backup_servers = talloc_steal(mem_ctx, state->backup_servers);
}
if (_num_backup_servers) {
*_num_backup_servers = state->num_backup_servers;
}
if (_dns_domain) {
*_dns_domain = talloc_steal(mem_ctx, state->dns_domain);
}
return EOK;
}
struct fo_resolve_srv_dns_ctx {
struct resolv_ctx *resolv_ctx;
enum restrict_family family_order;
enum host_database *host_dbs;
char *hostname;
char *sssd_domain;
char *detected_domain;
};
struct fo_resolve_srv_dns_state {
struct tevent_context *ev;
struct fo_resolve_srv_dns_ctx *ctx;
const char *service;
const char *protocol;
const char *discovery_domain;
char *dns_domain;
struct fo_server_info *servers;
size_t num_servers;
};
static void fo_resolve_srv_dns_domain_done(struct tevent_req *subreq);
static errno_t fo_resolve_srv_dns_discover(struct tevent_req *req);
static void fo_resolve_srv_dns_done(struct tevent_req *subreq);
struct fo_resolve_srv_dns_ctx *
fo_resolve_srv_dns_ctx_init(TALLOC_CTX *mem_ctx,
struct resolv_ctx *resolv_ctx,
enum restrict_family family_order,
enum host_database *host_dbs,
const char *hostname,
const char *sssd_domain)
{
struct fo_resolve_srv_dns_ctx *ctx = NULL;
ctx = talloc_zero(mem_ctx, struct fo_resolve_srv_dns_ctx);
if (ctx == NULL) {
return NULL;
}
ctx->resolv_ctx = resolv_ctx;
ctx->family_order = family_order;
ctx->host_dbs = host_dbs;
ctx->hostname = talloc_strdup(ctx, hostname);
if (ctx->hostname == NULL) {
goto fail;
}
ctx->sssd_domain = talloc_strdup(ctx, sssd_domain);
if (ctx->sssd_domain == NULL) {
goto fail;
}
return ctx;
fail:
talloc_free(ctx);
return NULL;
}
struct tevent_req *fo_resolve_srv_dns_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
const char *service,
const char *protocol,
const char *discovery_domain,
void *pvt)
{
struct fo_resolve_srv_dns_state *state = NULL;
struct fo_resolve_srv_dns_ctx *ctx = NULL;
struct tevent_req *req = NULL;
struct tevent_req *subreq = NULL;
errno_t ret;
req = tevent_req_create(mem_ctx, &state, struct fo_resolve_srv_dns_state);
if (req == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n"));
return NULL;
}
ctx = talloc_get_type(pvt, struct fo_resolve_srv_dns_ctx);
if (ctx == NULL) {
ret = EINVAL;
goto immediately;
}
state->ev = ev;
state->ctx = ctx;
state->service = service;
state->protocol = protocol;
if (discovery_domain == NULL) {
state->discovery_domain = NULL;
} else {
state->discovery_domain = discovery_domain;
}
if (discovery_domain == NULL && ctx->detected_domain == NULL) {
/* we will try to detect proper discovery domain */
subreq = resolv_get_domain_send(state, state->ev, ctx->resolv_ctx,
ctx->hostname, ctx->host_dbs,
ctx->family_order);
if (subreq == NULL) {
ret = ENOMEM;
goto immediately;
}
tevent_req_set_callback(subreq, fo_resolve_srv_dns_domain_done, req);
} else {
/* we will use either provided or previously detected
* discovery domain */
ret = fo_resolve_srv_dns_discover(req);
if (ret != EAGAIN) {
goto immediately;
}
}
return req;
immediately:
if (ret == EOK) {
tevent_req_done(req);
} else {
tevent_req_error(req, ret);
}
tevent_req_post(req, ev);
return req;
}
static void fo_resolve_srv_dns_domain_done(struct tevent_req *subreq)
{
struct fo_resolve_srv_dns_state *state = NULL;
struct tevent_req *req = NULL;
errno_t ret;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct fo_resolve_srv_dns_state);
ret = resolv_get_domain_recv(state->ctx, subreq,
&state->ctx->detected_domain);
talloc_zfree(subreq);
if (ret != EOK) {
goto done;
}
ret = fo_resolve_srv_dns_discover(req);
done:
if (ret == EOK) {
tevent_req_done(req);
} else if (ret != EAGAIN) {
tevent_req_error(req, ret);
}
return;
}
static errno_t fo_resolve_srv_dns_discover(struct tevent_req *req)
{
struct fo_resolve_srv_dns_state *state = NULL;
struct fo_resolve_srv_dns_ctx *ctx = NULL;
struct tevent_req *subreq = NULL;
const char **domains = NULL;
errno_t ret;
state = tevent_req_data(req, struct fo_resolve_srv_dns_state);
ctx = state->ctx;
domains = talloc_zero_array(state, const char *, 3);
if (domains == NULL) {
ret = ENOMEM;
goto done;
}
if (state->discovery_domain == NULL) {
/* we will use detected domain with SSSD domain as fallback */
domains[0] = talloc_strdup(domains, ctx->detected_domain);
if (domains[0] == NULL) {
ret = ENOMEM;
goto done;
}
if (strcasecmp(ctx->detected_domain, ctx->sssd_domain) != 0) {
domains[1] = talloc_strdup(domains, ctx->sssd_domain);
if (domains[1] == NULL) {
ret = ENOMEM;
goto done;
}
}
} else {
/* We will use only discovery domain that was provided via plugin
* interface. We don't have to dup here because it is already on
* state. */
domains[0] = state->discovery_domain;
}
subreq = fo_discover_srv_send(state, state->ev, ctx->resolv_ctx,
state->service, state->protocol, domains);
if (subreq == NULL) {
ret = ENOMEM;
goto done;
}
tevent_req_set_callback(subreq, fo_resolve_srv_dns_done, req);
ret = EAGAIN;
done:
if (ret != EAGAIN) {
talloc_free(domains);
}
return ret;
}
static void fo_resolve_srv_dns_done(struct tevent_req *subreq)
{
struct fo_resolve_srv_dns_state *state = NULL;
struct tevent_req *req = NULL;
errno_t ret;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct fo_resolve_srv_dns_state);
ret = fo_discover_srv_recv(state, subreq, &state->dns_domain,
&state->servers, &state->num_servers);
talloc_zfree(subreq);
if (ret != EOK) {
goto done;
}
done:
if (ret != EOK) {
tevent_req_error(req, ret);
return;
}
tevent_req_done(req);
}
errno_t fo_resolve_srv_dns_recv(TALLOC_CTX *mem_ctx,
struct tevent_req *req,
char **_dns_domain,
struct fo_server_info **_primary_servers,
size_t *_num_primary_servers,
struct fo_server_info **_backup_servers,
size_t *_num_backup_servers)
{
struct fo_resolve_srv_dns_state *state = NULL;
state = tevent_req_data(req, struct fo_resolve_srv_dns_state);
TEVENT_REQ_RETURN_ON_ERROR(req);
if (_primary_servers) {
*_primary_servers = talloc_steal(mem_ctx, state->servers);
}
if (_num_primary_servers) {
*_num_primary_servers = state->num_servers;
}
/* backup servers are not supported by simple srv lookup */
if (_backup_servers) {
*_backup_servers = NULL;
}
if (_num_backup_servers) {
*_num_backup_servers = 0;
}
if (_dns_domain) {
*_dns_domain = talloc_steal(mem_ctx, state->dns_domain);
}
return EOK;
}