diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 05:31:45 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 05:31:45 +0000 |
commit | 74aa0bc6779af38018a03fd2cf4419fe85917904 (patch) | |
tree | 9cb0681aac9a94a49c153d5823e7a55d1513d91f /src/responder/common/responder_get_domains.c | |
parent | Initial commit. (diff) | |
download | sssd-74aa0bc6779af38018a03fd2cf4419fe85917904.tar.xz sssd-74aa0bc6779af38018a03fd2cf4419fe85917904.zip |
Adding upstream version 2.9.4.upstream/2.9.4
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/responder/common/responder_get_domains.c')
-rw-r--r-- | src/responder/common/responder_get_domains.c | 841 |
1 files changed, 841 insertions, 0 deletions
diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c new file mode 100644 index 0000000..1a388e7 --- /dev/null +++ b/src/responder/common/responder_get_domains.c @@ -0,0 +1,841 @@ +/* + Authors: + Jan Zeleny <jzeleny@redhat.com> + + Copyright (C) 2011 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "util/util.h" +#include "util/sss_chain_id.h" +#include "responder/common/responder.h" +#include "providers/data_provider.h" +#include "db/sysdb.h" +#include "sss_iface/sss_iface_async.h" + +/* ========== Get subdomains for a domain ================= */ +struct get_subdomains_state { + uint16_t dp_error; + uint32_t error; + const char *error_message; +}; + +static void get_subdomains_done(struct tevent_req *subreq); + +struct tevent_req * +get_subdomains_send(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + struct sss_domain_info *dom, + const char *hint) +{ + struct get_subdomains_state *state; + struct tevent_req *subreq; + struct tevent_req *req; + struct be_conn *be_conn; + errno_t ret; + + req = tevent_req_create(mem_ctx, &state, struct get_subdomains_state); + if (req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); + return NULL; + } + + if (is_files_provider(dom)) { + DEBUG(SSSDBG_TRACE_INTERNAL, "Domain %s does not check DP\n", + dom->name); + state->dp_error = DP_ERR_OK; + state->error = EOK; + state->error_message = talloc_strdup(state, "Success"); + if (state->error_message == NULL) { + ret = ENOMEM; + goto done; + } + ret = EOK; + goto done; + } + + ret = sss_dp_get_domain_conn(rctx, dom->conn_name, &be_conn); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "BUG: The Data Provider connection for %s is not available!\n", + dom->name); + ret = EIO; + goto done; + } + + subreq = sbus_call_dp_dp_getDomains_send(state, be_conn->conn, + be_conn->bus_name, + SSS_BUS_PATH, hint); + if (subreq == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create subrequest!\n"); + ret = ENOMEM; + goto done; + } + + tevent_req_set_callback(subreq, get_subdomains_done, req); + + ret = EAGAIN; + +done: +#ifdef BUILD_FILES_PROVIDER + if (ret == EOK) { + tevent_req_done(req); + tevent_req_post(req, rctx->ev); + } else +#endif + if (ret != EAGAIN) { + tevent_req_error(req, ret); + tevent_req_post(req, rctx->ev); + } + + return req; +} + +static void get_subdomains_done(struct tevent_req *subreq) +{ + struct get_subdomains_state *state; + struct tevent_req *req; + errno_t ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct get_subdomains_state); + + ret = sbus_call_dp_dp_getDomains_recv(state, subreq, &state->dp_error, + &state->error, &state->error_message); + talloc_zfree(subreq); + if (ret != EOK) { + state->dp_error = DP_ERR_FATAL; + state->error = ret; + } + + tevent_req_done(req); + return; +} + +static errno_t +get_subdomains_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + uint16_t *_dp_error, + uint32_t *_error, + const char **_error_message) +{ + struct get_subdomains_state *state; + state = tevent_req_data(req, struct get_subdomains_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + + *_dp_error = state->dp_error; + *_error = state->error; + *_error_message = talloc_steal(mem_ctx, state->error_message); + + return EOK; +} + +/* ====== Iterate over all domains, searching for their subdomains ======= */ +static errno_t process_subdomains(struct sss_domain_info *dom, + struct confdb_ctx *confdb); +static void set_time_of_last_request(struct resp_ctx *rctx); +static errno_t check_last_request(struct resp_ctx *rctx, const char *hint); + +struct sss_dp_get_domains_state { + struct resp_ctx *rctx; + struct sss_domain_info *dom; + const char *hint; +}; + +static void +sss_dp_get_domains_process(struct tevent_req *subreq); + +struct tevent_req *sss_dp_get_domains_send(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + bool force, + const char *hint) +{ + errno_t ret; + struct tevent_req *req; + struct tevent_req *subreq; + struct sss_dp_get_domains_state *state; + bool refresh_timeout = false; + + req = tevent_req_create(mem_ctx, &state, struct sss_dp_get_domains_state); + if (req == NULL) { + return NULL; + } + + if (rctx->domains == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "No domains configured.\n"); + ret = EINVAL; + goto immediately; + } + + if (!force) { + ret = check_last_request(rctx, hint); + if (ret == EOK) { + DEBUG(SSSDBG_TRACE_FUNC, + "Last call was too recent, nothing to do!\n"); + goto immediately; + } else if (ret != EAGAIN) { + DEBUG(SSSDBG_TRACE_FUNC, "check_domain_request failed with [%d][%s]\n", + ret, strerror(ret)); + goto immediately; + } + } + refresh_timeout = true; + + state->rctx = rctx; + if (hint != NULL) { + state->hint = hint; + } else { + state->hint = talloc_strdup(state, ""); + if (state->hint == NULL) { + ret = ENOMEM; + goto immediately; + } + } + + state->dom = rctx->domains; + while(is_files_provider(state->dom)) { + state->dom = get_next_domain(state->dom, 0); + } + + if (state->dom == NULL) { + /* All domains were local */ + ret = sss_resp_populate_cr_domains(state->rctx); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "sss_resp_populate_cr_domains() failed [%d]: [%s]\n", + ret, sss_strerror(ret)); + goto immediately; + } + ret = EOK; + goto immediately; + } + + subreq = get_subdomains_send(req, rctx, state->dom, state->hint); + if (subreq == NULL) { + ret = ENOMEM; + goto immediately; + } + tevent_req_set_callback(subreq, sss_dp_get_domains_process, req); + + return req; + +immediately: + if (ret == EOK) { + if (refresh_timeout) { + set_time_of_last_request(rctx); + } + tevent_req_done(req); + } else { + tevent_req_error(req, ret); + } + tevent_req_post(req, rctx->ev); + + return req; +} + +static void sss_resp_update_certmaps(struct resp_ctx *rctx) +{ + int ret; + struct certmap_info **certmaps; + bool user_name_hint; + struct sss_domain_info *dom; + + for (dom = rctx->domains; dom != NULL; dom = dom->next) { + ret = sysdb_get_certmap(dom, dom->sysdb, &certmaps, &user_name_hint); + if (ret == EOK) { + dom->user_name_hint = user_name_hint; + talloc_free(dom->certmaps); + dom->certmaps = certmaps; + } else { + DEBUG(SSSDBG_OP_FAILURE, + "sysdb_get_certmap failed for domain [%s].\n", dom->name); + } + } +} + +static void +sss_dp_get_domains_process(struct tevent_req *subreq) +{ + errno_t ret; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sss_dp_get_domains_state *state = tevent_req_data(req, + struct sss_dp_get_domains_state); + uint16_t dp_err; + uint32_t dp_ret; + const char *err_msg; + + ret = get_subdomains_recv(subreq, subreq, &dp_err, &dp_ret, &err_msg); + talloc_zfree(subreq); + if (ret != EOK) { + goto fail; + } + + ret = process_subdomains(state->dom, state->rctx->cdb); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "process_subdomains failed, " + "trying next domain.\n"); + goto fail; + } + + /* Advance to the next domain */ + state->dom = get_next_domain(state->dom, 0); + + /* Skip "files provider" */ + while(is_files_provider(state->dom)) { + state->dom = get_next_domain(state->dom, 0); + } + + if (state->dom == NULL) { + /* No more domains to check, refreshing the active configuration */ + set_time_of_last_request(state->rctx); + ret = sss_resp_populate_cr_domains(state->rctx); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "sss_resp_populate_cr_domains() failed [%d]: [%s]\n", + ret, sss_strerror(ret)); + goto fail; + } + + sss_resp_update_certmaps(state->rctx); + + ret = sss_ncache_reset_repopulate_permanent(state->rctx, + state->rctx->ncache); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "sss_ncache_reset_repopulate_permanent failed, ignored.\n"); + } + + tevent_req_done(req); + return; + } + + subreq = get_subdomains_send(req, state->rctx, state->dom, state->hint); + if (subreq == NULL) { + ret = ENOMEM; + goto fail; + } + tevent_req_set_callback(subreq, sss_dp_get_domains_process, req); + return; + +fail: + tevent_req_error(req, ret); + return; +} + +static errno_t +process_subdomains(struct sss_domain_info *domain, struct confdb_ctx *confdb) +{ + int ret; + + if (domain->realm == NULL || + domain->flat_name == NULL || + domain->domain_id == NULL) { + ret = sysdb_master_domain_update(domain); + if (ret != EOK) { + DEBUG(SSSDBG_FUNC_DATA, "sysdb_master_domain_get_info " \ + "failed.\n"); + goto done; + } + } + + /* Retrieve all subdomains of this domain from sysdb + * and create their struct sss_domain_info representations + */ + ret = sysdb_update_subdomains(domain, confdb); + if (ret != EOK) { + DEBUG(SSSDBG_FUNC_DATA, "sysdb_update_subdomains failed.\n"); + goto done; + } + + errno = 0; + ret = gettimeofday(&domain->subdomains_last_checked, NULL); + if (ret == -1) { + ret = errno; + goto done; + } + + ret = EOK; + +done: + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to update sub-domains " + "of domain [%s].\n", domain->name); + } + + return ret; +} + +errno_t sss_dp_get_domains_recv(struct tevent_req *req) +{ + TEVENT_REQ_RETURN_ON_ERROR(req); + + return EOK; +} + +static void set_time_of_last_request(struct resp_ctx *rctx) +{ + int ret; + + errno = 0; + ret = gettimeofday(&rctx->get_domains_last_call, NULL); + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_TRACE_FUNC, "gettimeofday failed [%d][%s].\n", + ret, strerror(ret)); + } +} + +static errno_t check_last_request(struct resp_ctx *rctx, const char *hint) +{ + struct sss_domain_info *dom; + time_t now = time(NULL); + time_t diff; + + diff = now - rctx->get_domains_last_call.tv_sec; + if (diff >= rctx->domains_timeout) { + /* Timeout, expired, fetch domains again */ + return EAGAIN; + } + + if (hint != NULL) { + for (dom = rctx->domains; dom; + dom = get_next_domain(dom, SSS_GND_DESCEND)) { + if (!IS_SUBDOMAIN(dom)) { + diff = now - dom->subdomains_last_checked.tv_sec; + /* not a subdomain */ + continue; + } + if (strcasecmp(dom->name, hint) == 0) { + if (diff >= rctx->domains_timeout) { + /* Timeout, expired, fetch domains again */ + return EAGAIN; + } + } + } + } + + return EOK; +} + +struct get_domains_state { + struct resp_ctx *rctx; + struct sss_nc_ctx *optional_ncache; + get_domains_callback_fn_t *callback; + void *callback_pvt; +}; + +static void get_domains_at_startup_done(struct tevent_req *req) +{ + int ret; + struct get_domains_state *state; + + state = tevent_req_callback_data(req, struct get_domains_state); + + ret = sss_dp_get_domains_recv(req); + talloc_free(req); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, "sss_dp_get_domains request failed.\n"); + } + + if (state->optional_ncache != NULL) { + ret = sss_ncache_reset_repopulate_permanent(state->rctx, + state->optional_ncache); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + "sss_ncache_reset_repopulate_permanent failed.\n"); + } + } + + if (is_files_provider(state->rctx->domains)) { + ret = sysdb_master_domain_update(state->rctx->domains); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sysdb_master_domain_update failed, " + "ignored.\n"); + } + } + + if (state->callback != NULL) { + state->callback(state->callback_pvt); + } + + talloc_free(state); + return; +} + +static void get_domains_at_startup(struct tevent_context *ev, + struct tevent_immediate *imm, + void *pvt) +{ + struct tevent_req *req; + struct get_domains_state *state; + + state = talloc_get_type(pvt, struct get_domains_state); + + req = sss_dp_get_domains_send(state, state->rctx, true, NULL); + if (req == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "sss_dp_get_domains_send failed.\n"); + talloc_free(state); + return; + } + + tevent_req_set_callback(req, get_domains_at_startup_done, state); + return; +} + +errno_t schedule_get_domains_task(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct resp_ctx *rctx, + struct sss_nc_ctx *optional_ncache, + get_domains_callback_fn_t *callback, + void *callback_pvt) +{ + struct tevent_immediate *imm; + struct get_domains_state *state; + + state = talloc(mem_ctx, struct get_domains_state); + if (state == NULL) { + return ENOMEM; + } + state->rctx = rctx; + state->optional_ncache = optional_ncache; + state->callback = callback; + state->callback_pvt = callback_pvt; + + imm = tevent_create_immediate(mem_ctx); + if (imm == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "tevent_create_immediate failed.\n"); + talloc_free(state); + return ENOMEM; + } + + tevent_schedule_immediate(imm, ev, get_domains_at_startup, state); + + return EOK; +} + +struct sss_parse_inp_state { + struct resp_ctx *rctx; + const char *default_domain; + const char *rawinp; + + char *name; + char *domname; + errno_t error; +}; + +static void sss_parse_inp_done(struct tevent_req *subreq); + +struct tevent_req * +sss_parse_inp_send(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + const char *default_domain, + const char *rawinp) +{ + errno_t ret; + struct tevent_req *req; + struct tevent_req *subreq; + struct sss_parse_inp_state *state; + + req = tevent_req_create(mem_ctx, &state, struct sss_parse_inp_state); + if (req == NULL) { + return NULL; + } + + if (rawinp == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Empty input!\n"); + ret = EINVAL; + goto done; + } + + state->rctx = rctx; + + state->rawinp = talloc_strdup(state, rawinp); + if (state->rawinp == NULL) { + ret = ENOMEM; + goto done; + } + + + state->default_domain = talloc_strdup(state, default_domain); + if (default_domain != NULL && state->default_domain == NULL) { + ret = ENOMEM; + goto done; + } + + /* If the subdomains haven't been checked yet, we need to always + * attach to the post-startup subdomain request and only then parse + * the input. Otherwise, we might not be able to parse input with a + * flat domain name specifier */ + if (rctx->get_domains_last_call.tv_sec > 0) { + ret = sss_parse_name_for_domains(state, rctx->domains, + default_domain, rawinp, + &state->domname, &state->name); + if (ret == EOK) { + /* Was able to use cached domains */ + goto done; + } else if (ret != EAGAIN) { + DEBUG(SSSDBG_OP_FAILURE, "Invalid name received [%s]\n", rawinp); + ret = ERR_INPUT_PARSE; + goto done; + } + } + + /* EAGAIN - check the DP for subdomains */ + + DEBUG(SSSDBG_FUNC_DATA, "Requesting info for [%s] from [%s]\n", + state->name, state->domname ? state->domname : "<ALL>"); + + /* We explicitly use force=false here. This request should decide itself + * if it's time to re-use the cached subdomain list or refresh. If the + * caller needs to specify the 'force' parameter, they should use the + * sss_dp_get_domains_send() request itself + */ + subreq = sss_dp_get_domains_send(state, rctx, false, state->domname); + if (subreq == NULL) { + ret = ENOMEM; + goto done; + } + tevent_req_set_callback(subreq, sss_parse_inp_done, req); + return req; + +done: + if (ret == EOK) { + tevent_req_done(req); + } else { + tevent_req_error(req, ret); + } + tevent_req_post(req, rctx->ev); + return req; +} + +static void sss_parse_inp_done(struct tevent_req *subreq) +{ + errno_t ret; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sss_parse_inp_state *state = tevent_req_data(req, + struct sss_parse_inp_state); + + ret = sss_dp_get_domains_recv(subreq); + talloc_free(subreq); + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + + state->error = ERR_OK; + + ret = sss_parse_name_for_domains(state, state->rctx->domains, + state->default_domain, + state->rawinp, + &state->domname, &state->name); + if (ret == EAGAIN && state->domname != NULL && state->name == NULL) { + DEBUG(SSSDBG_FUNC_DATA, + "Unknown domain in [%s]\n", state->rawinp); + state->error = ERR_DOMAIN_NOT_FOUND; + } else if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Invalid name received [%s]\n", state->rawinp); + state->error = ERR_INPUT_PARSE; + } + + if (state->error != ERR_OK) { + tevent_req_error(req, state->error); + return; + } + + /* Was able to parse the name now */ + tevent_req_done(req); +} + +errno_t sss_parse_inp_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + char **_name, char **_domname) +{ + struct sss_parse_inp_state *state = tevent_req_data(req, + struct sss_parse_inp_state); + + if (state->error != ERR_DOMAIN_NOT_FOUND) { + TEVENT_REQ_RETURN_ON_ERROR(req); + } + + if (_name) { + *_name = talloc_steal(mem_ctx, state->name); + } + + if (_domname) { + *_domname = talloc_steal(mem_ctx, state->domname); + } + + return state->error; +} + +/* ========== Get domain of an account ================= */ + + +struct sss_dp_get_account_domain_state { + uint16_t dp_error; + uint32_t error; + const char *domain_name; +}; + +static void sss_dp_get_account_domain_done(struct tevent_req *subreq); + +struct tevent_req * +sss_dp_get_account_domain_send(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + struct sss_domain_info *dom, + bool fast_reply, + enum sss_dp_acct_type type, + uint32_t opt_id, + const char *opt_str) +{ + struct sss_dp_get_account_domain_state *state; + struct tevent_req *subreq; + struct tevent_req *req; + struct be_conn *be_conn; + uint32_t entry_type; + char *filter; + uint32_t dp_flags; + errno_t ret; + + req = tevent_req_create(mem_ctx, &state, struct sss_dp_get_account_domain_state); + if (req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); + return NULL; + } + + ret = sss_dp_get_domain_conn(rctx, dom->conn_name, &be_conn); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "BUG: The Data Provider connection for %s is not available!\n", + dom->name); + ret = EIO; + goto done; + } + + switch (type) { + case SSS_DP_USER: + entry_type = BE_REQ_USER; + break; + case SSS_DP_GROUP: + entry_type = BE_REQ_GROUP; + break; + case SSS_DP_USER_AND_GROUP: + entry_type = BE_REQ_USER_AND_GROUP; + break; + case SSS_DP_SECID: + entry_type = BE_REQ_BY_SECID; + break; + default: + DEBUG(SSSDBG_OP_FAILURE, + "Unsupported lookup type %X for this request\n", type); + return NULL; + } + + if (type == SSS_DP_SECID) { + if (opt_str == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + "BUG: SID search called without SID parameter!\n"); + ret = EINVAL; + goto done; + } + filter = talloc_asprintf(state, DP_SEC_ID"=%s", opt_str); + } else { + filter = talloc_asprintf(state, "idnumber=%u", opt_id); + } + if (filter == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n"); + ret = ENOMEM; + goto done; + } + + dp_flags = fast_reply ? DP_FAST_REPLY : 0; + + subreq = sbus_call_dp_dp_getAccountDomain_send(state, be_conn->conn, + be_conn->bus_name, + SSS_BUS_PATH, dp_flags, + entry_type, filter, + sss_chain_id_get()); + if (subreq == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create subrequest!\n"); + ret = ENOMEM; + goto done; + } + + tevent_req_set_callback(subreq, sss_dp_get_account_domain_done, req); + + ret = EAGAIN; + +done: + if (ret != EAGAIN) { + tevent_req_error(req, ret); + tevent_req_post(req, rctx->ev); + } + + return req; +} + +static void sss_dp_get_account_domain_done(struct tevent_req *subreq) +{ + struct sss_dp_get_account_domain_state *state; + struct tevent_req *req; + errno_t ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sss_dp_get_account_domain_state); + + ret = sbus_call_dp_dp_getAccountDomain_recv(state, subreq, &state->dp_error, + &state->error, + &state->domain_name); + talloc_zfree(subreq); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Could not get account info [%d]: %s\n", + ret, sss_strerror(ret)); + tevent_req_error(req, ret); + return; + } + + if (state->dp_error != DP_ERR_OK) { + DEBUG(state->error == ERR_GET_ACCT_DOM_NOT_SUPPORTED ? SSSDBG_TRACE_INTERNAL + : SSSDBG_IMPORTANT_INFO, + "Data Provider Error: %u, %u [%s]\n", + (unsigned int)state->dp_error, (unsigned int)state->error, + sss_strerror(state->error)); + tevent_req_error(req, state->error ? state->error : EIO); + return; + } + + tevent_req_done(req); + return; +} + +errno_t sss_dp_get_account_domain_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + char **_domain) +{ + struct sss_dp_get_account_domain_state *state; + state = tevent_req_data(req, struct sss_dp_get_account_domain_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + + *_domain = talloc_strdup(mem_ctx, state->domain_name); + if (*_domain == NULL) { + return ENOMEM; + } + + return EOK; +} |