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_dp.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_dp.c')
-rw-r--r-- | src/responder/common/responder_dp.c | 460 |
1 files changed, 460 insertions, 0 deletions
diff --git a/src/responder/common/responder_dp.c b/src/responder/common/responder_dp.c new file mode 100644 index 0000000..227a229 --- /dev/null +++ b/src/responder/common/responder_dp.c @@ -0,0 +1,460 @@ +/* + Authors: + Simo Sorce <ssorce@redhat.com> + Stephen Gallagher <sgallagh@redhat.com> + + Copyright (C) 2009 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 <sys/time.h> +#include <time.h> +#include "util/util.h" +#include "util/sss_chain_id.h" +#include "responder/common/responder_packet.h" +#include "responder/common/responder.h" +#include "providers/data_provider.h" + +#ifdef BUILD_FILES_PROVIDER +static errno_t +sss_dp_account_files_params(struct sss_domain_info *dom, + enum sss_dp_acct_type type_in, + const char *opt_name_in, + enum sss_dp_acct_type *_type_out, + const char **_opt_name_out) +{ + if (type_in != SSS_DP_CERT) { + if (sss_domain_get_state(dom) != DOM_INCONSISTENT) { + DEBUG(SSSDBG_TRACE_INTERNAL, + "The entries in the files domain are up-to-date\n"); + return EOK; + } + + if (sss_domain_fallback_to_nss(dom)) { + DEBUG(SSSDBG_TRACE_INTERNAL, + "Domain files is not consistent, falling back to nss.\n"); + return ENOENT; + } + + DEBUG(SSSDBG_TRACE_INTERNAL, + "Domain files is not consistent, issuing update\n"); + } + + switch(type_in) { + case SSS_DP_USER: + case SSS_DP_GROUP: + *_type_out = type_in; + *_opt_name_out = NULL; + return EAGAIN; + case SSS_DP_INITGROUPS: + /* There is no initgroups enumeration so let's use a dummy + * name to let the DP chain the requests + */ + *_type_out = type_in; + *_opt_name_out = DP_REQ_OPT_FILES_INITGR; + return EAGAIN; + case SSS_DP_CERT: + /* Let the backend handle certificate mapping for local users */ + *_type_out = type_in; + *_opt_name_out = opt_name_in; + return EAGAIN; + /* These are not handled by the files provider, just fall back */ + case SSS_DP_SUBID_RANGES: + case SSS_DP_NETGR: + case SSS_DP_SERVICES: + case SSS_DP_SECID: + case SSS_DP_USER_AND_GROUP: + case SSS_DP_WILDCARD_USER: + case SSS_DP_WILDCARD_GROUP: + return EOK; + } + + DEBUG(SSSDBG_CRIT_FAILURE, "Unhandled type %d\n", type_in); + return EINVAL; +} +#endif + +static errno_t +sss_dp_get_account_filter(TALLOC_CTX *mem_ctx, + enum sss_dp_acct_type type, + bool fast_reply, + const char *opt_name, + uint32_t opt_id, + uint32_t *_dp_flags, + uint32_t *_entry_type, + char **_filter) +{ + uint32_t entry_type = 0; + uint32_t dp_flags; + char *filter; + + switch (type) { + case SSS_DP_USER: + case SSS_DP_WILDCARD_USER: + entry_type = BE_REQ_USER; + break; + case SSS_DP_GROUP: + case SSS_DP_WILDCARD_GROUP: + entry_type = BE_REQ_GROUP; + break; + case SSS_DP_INITGROUPS: + entry_type = BE_REQ_INITGROUPS; + break; + case SSS_DP_SUBID_RANGES: + entry_type = BE_REQ_SUBID_RANGES; + break; + case SSS_DP_NETGR: + entry_type = BE_REQ_NETGROUP; + break; + case SSS_DP_SERVICES: + entry_type = BE_REQ_SERVICES; + break; + case SSS_DP_SECID: + entry_type = BE_REQ_BY_SECID; + break; + case SSS_DP_USER_AND_GROUP: + entry_type = BE_REQ_USER_AND_GROUP; + break; + case SSS_DP_CERT: + entry_type = BE_REQ_BY_CERT; + break; + } + + dp_flags = fast_reply ? DP_FAST_REPLY : 0; + + if (opt_name != NULL) { + switch(type) { + case SSS_DP_SECID: + filter = talloc_asprintf(mem_ctx, "%s=%s", DP_SEC_ID, + opt_name); + break; + case SSS_DP_CERT: + filter = talloc_asprintf(mem_ctx, "%s=%s", DP_CERT, + opt_name); + break; + case SSS_DP_WILDCARD_USER: + case SSS_DP_WILDCARD_GROUP: + filter = talloc_asprintf(mem_ctx, "%s=%s", DP_WILDCARD, + opt_name); + break; + default: + filter = talloc_asprintf(mem_ctx, "name=%s", opt_name); + break; + } + } else if (opt_id != 0) { + filter = talloc_asprintf(mem_ctx, "idnumber=%u", opt_id); + } else { + filter = talloc_strdup(mem_ctx, ENUM_INDICATOR); + } + + if (filter == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n"); + return ENOMEM; + } + + *_dp_flags = dp_flags; + *_entry_type = entry_type; + *_filter = filter; + + return EOK; +} + +struct sss_dp_get_account_state { + uint16_t dp_error; + uint32_t error; + const char *error_message; +}; + +static void sss_dp_get_account_done(struct tevent_req *subreq); + +struct tevent_req * +sss_dp_get_account_send(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + struct sss_domain_info *dom, + bool fast_reply, + enum sss_dp_acct_type type, + const char *opt_name, + uint32_t opt_id, + const char *extra) +{ + struct sss_dp_get_account_state *state; + struct tevent_req *subreq; + struct tevent_req *req; + struct be_conn *be_conn; + uint32_t entry_type; + uint32_t dp_flags; + char *filter; + errno_t ret; + + req = tevent_req_create(mem_ctx, &state, struct sss_dp_get_account_state); + if (req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); + return NULL; + } + + /* either, or, not both */ + if (opt_name != NULL && opt_id != 0) { + ret = EINVAL; + goto done; + } + + if (dom == NULL) { + ret = EINVAL; + goto done; + } + +#ifdef BUILD_FILES_PROVIDER + if (is_files_provider(dom)) { + /* This is a special case. If the files provider is just being updated, + * we issue an enumeration request. We always use the same request type + * (user enumeration) to make sure concurrent requests are just chained + * in the Data Provider */ + ret = sss_dp_account_files_params(dom, type, opt_name, + &type, &opt_name); + if (ret == EOK) { + 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; + } + goto done; + } else if (ret != EAGAIN) { + DEBUG((ret == ENOENT) ? SSSDBG_MINOR_FAILURE : SSSDBG_OP_FAILURE, + "Failed to set files provider update [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } + /* EAGAIN, fall through to issuing the request */ + } +#endif + + 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; + } + + /* Build filter. */ + ret = sss_dp_get_account_filter(state, type, fast_reply, opt_name, opt_id, + &dp_flags, &entry_type, &filter); + if (ret != EOK) { + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, + "Creating request for [%s][%#x][%s][%s:%s]\n", + dom->name, entry_type, be_req2str(entry_type), + filter, extra == NULL ? "-" : extra); + + subreq = sbus_call_dp_dp_getAccountInfo_send(state, be_conn->conn, + be_conn->bus_name, SSS_BUS_PATH, dp_flags, + entry_type, filter, dom->name, extra, + 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_done, req); + + ret = EAGAIN; + +done: + if (ret == EOK) { + tevent_req_done(req); + tevent_req_post(req, rctx->ev); + } else if (ret != EAGAIN) { + tevent_req_error(req, ret); + tevent_req_post(req, rctx->ev); + } + + return req; +} + +static void sss_dp_get_account_done(struct tevent_req *subreq) +{ + struct sss_dp_get_account_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_state); + + ret = sbus_call_dp_dp_getAccountInfo_recv(state, subreq, &state->dp_error, + &state->error, + &state->error_message); + talloc_zfree(subreq); + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); + return; +} + +errno_t +sss_dp_get_account_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + uint16_t *_dp_error, + uint32_t *_error, + const char **_error_message) +{ + struct sss_dp_get_account_state *state; + state = tevent_req_data(req, struct sss_dp_get_account_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; +} + +struct sss_dp_resolver_get_state { + uint16_t dp_error; + uint32_t error; + const char *error_message; +}; + +static void sss_dp_resolver_get_done(struct tevent_req *subreq); + +struct tevent_req * +sss_dp_resolver_get_send(TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + struct sss_domain_info *dom, + bool fast_reply, + uint32_t entry_type, + uint32_t filter_type, + const char *filter_value) +{ + struct sss_dp_resolver_get_state *state; + struct tevent_req *req; + struct tevent_req *subreq; + struct be_conn *be_conn; + uint32_t dp_flags; + errno_t ret; + + req = tevent_req_create(mem_ctx, &state, struct sss_dp_resolver_get_state); + if (req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); + return NULL; + } + + /* Validate filter_type */ + switch (filter_type) { + case BE_FILTER_NAME: + case BE_FILTER_ADDR: + case BE_FILTER_ENUM: + break; + default: + ret = EINVAL; + goto done; + } + + if (dom == NULL) { + ret = EINVAL; + 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; + } + + DEBUG(SSSDBG_TRACE_FUNC, + "Creating request for [%s][%#x][%s][%#x:%s]\n", + dom->name, entry_type, be_req2str(entry_type), + filter_type, filter_value ? filter_value : "-"); + + dp_flags = fast_reply ? DP_FAST_REPLY : 0; + subreq = sbus_call_dp_dp_resolverHandler_send(state, be_conn->conn, + be_conn->bus_name, + SSS_BUS_PATH, + dp_flags, entry_type, + filter_type, filter_value, + 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_resolver_get_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_resolver_get_done(struct tevent_req *subreq) +{ + struct sss_dp_resolver_get_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_resolver_get_state); + + ret = sbus_call_dp_dp_resolverHandler_recv(state, subreq, + &state->dp_error, + &state->error, + &state->error_message); + talloc_zfree(subreq); + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); + return; +} + +errno_t +sss_dp_resolver_get_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + uint16_t *_dp_error, + uint32_t *_error, + const char **_error_message) +{ + struct sss_dp_resolver_get_state *state; + state = tevent_req_data(req, struct sss_dp_resolver_get_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; +} |