ipa_subdomains_id.c revision ed4a9bd4d0f7fb359bed66a8d63a92e7be633aae
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina/*
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina SSSD
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina IPA Identity Backend Module for sub-domains
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina Authors:
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina Sumit Bose <sbose@redhat.com>
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina Copyright (C) 2012 Red Hat
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina This program is free software; you can redistribute it and/or modify
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina it under the terms of the GNU General Public License as published by
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina the Free Software Foundation; either version 3 of the License, or
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina (at your option) any later version.
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina This program is distributed in the hope that it will be useful,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina but WITHOUT ANY WARRANTY; without even the implied warranty of
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina GNU General Public License for more details.
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina You should have received a copy of the GNU General Public License
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina along with this program. If not, see <http://www.gnu.org/licenses/>.
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina*/
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina#include <errno.h>
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina#include "util/util.h"
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina#include "util/sss_nss.h"
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina#include "util/strtonum.h"
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina#include "db/sysdb.h"
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina#include "providers/ldap/ldap_common.h"
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina#include "providers/ldap/sdap_async.h"
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina#include "providers/ipa/ipa_id.h"
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina#include "providers/ad/ad_id.h"
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina#include "providers/ipa/ipa_subdomains.h"
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březinastruct ipa_subdomain_account_state {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct tevent_context *ev;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct ipa_id_ctx *ipa_ctx;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct sdap_id_ctx *ctx;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct sdap_id_op *op;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct sysdb_ctx *sysdb;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct sss_domain_info *domain;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct be_req *be_req;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct be_acct_req *ar;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina bool ipa_server_mode;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina int entry_type;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina const char *filter;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina int filter_type;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct sysdb_attrs *override_attrs;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina int dp_error;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina};
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březinastatic void ipa_subdomain_account_connected(struct tevent_req *subreq);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březinastatic void ipa_subdomain_account_got_override(struct tevent_req *subreq);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březinastatic void ipa_subdomain_account_done(struct tevent_req *subreq);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březinastatic errno_t ipa_subdomain_account_get_original_step(struct tevent_req *req,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct be_acct_req *ar);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březinastruct tevent_req *ipa_subdomain_account_send(TALLOC_CTX *memctx,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct tevent_context *ev,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct ipa_id_ctx *ipa_ctx,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct be_req *be_req,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct be_acct_req *ar)
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina{
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct tevent_req *req;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct ipa_subdomain_account_state *state;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct tevent_req *subreq;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina int ret;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina req = tevent_req_create(memctx, &state, struct ipa_subdomain_account_state);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina if (req == NULL) {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina DEBUG(SSSDBG_OP_FAILURE, "tevent_req_create failed.\n");
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina return NULL;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina }
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina state->ev = ev;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina state->ipa_ctx = ipa_ctx;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina state->ctx = ipa_ctx->sdap_id_ctx;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina state->dp_error = DP_ERR_FATAL;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina state->op = sdap_id_op_create(state, state->ctx->conn->conn_cache);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina if (!state->op) {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina ret = ENOMEM;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina goto fail;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina }
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina state->domain = find_domain_by_name(state->ctx->be->domain,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina ar->domain, true);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina if (state->domain == NULL) {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina DEBUG(SSSDBG_OP_FAILURE, "find_domain_by_name failed.\n");
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina ret = ENOMEM;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina goto fail;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina }
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina state->sysdb = state->domain->sysdb;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina state->be_req = be_req;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina state->ar = ar;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina state->ipa_server_mode = dp_opt_get_bool(state->ipa_ctx->ipa_options->basic,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina IPA_SERVER_MODE);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina state->override_attrs = NULL;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina /* With views we cannot got directly to the look up the AD objects but
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina * have to check first if the request matches an override in the given
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina * view. But there are cases where this can be skipped and the AD object
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina * can be searched directly:
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina * - searches by SID: because we do not override the SID
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina * - if the responder does not send the EXTRA_INPUT_MAYBE_WITH_VIEW flags,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina * because in this case the entry was found in the cache and the
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina * original value is used for the search (e.g. during cache updates) */
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina if (state->ar->filter_type == BE_FILTER_SECID
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina || (!state->ipa_server_mode
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina && state->ar->extra_value != NULL
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina && strcmp(state->ar->extra_value,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina EXTRA_INPUT_MAYBE_WITH_VIEW) != 0 )) {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina ret = ipa_subdomain_account_get_original_step(req, state->ar);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina if (ret != EOK) {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina DEBUG(SSSDBG_OP_FAILURE,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina "ipa_subdomain_account_get_original_step failed.\n");
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina goto fail;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina }
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina return req;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina }
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina subreq = sdap_id_op_connect_send(state->op, state, &ret);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina if (!subreq) {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina goto fail;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina }
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina tevent_req_set_callback(subreq, ipa_subdomain_account_connected, req);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina return req;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březinafail:
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina tevent_req_error(req, ret);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina tevent_req_post(req, ev);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina return req;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina}
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březinastatic void ipa_subdomain_account_connected(struct tevent_req *subreq)
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina{
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct tevent_req *req = tevent_req_callback_data(subreq,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct tevent_req);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct ipa_subdomain_account_state *state = tevent_req_data(req,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct ipa_subdomain_account_state);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina int dp_error = DP_ERR_FATAL;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina int ret;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina ret = sdap_id_op_connect_recv(subreq, &dp_error);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina talloc_zfree(subreq);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina if (ret != EOK) {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect request failed.\n");
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina goto fail;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina }
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina subreq = ipa_get_ad_override_send(state, state->ev, state->ctx,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina state->ipa_ctx->ipa_options,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina dp_opt_get_string(state->ipa_ctx->ipa_options->basic,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina IPA_KRB5_REALM),
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina state->ipa_ctx->view_name, state->ar);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina if (subreq == NULL) {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_override_send failed.\n");
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina ret = ENOMEM;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina goto fail;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina }
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina tevent_req_set_callback(subreq, ipa_subdomain_account_got_override, req);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina return;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březinafail:
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina state->dp_error = dp_error;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina tevent_req_error(req, ret);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina return;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina}
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina#define OVERRIDE_ANCHOR_SID_PREFIX ":SID:"
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina#define OVERRIDE_ANCHOR_SID_PREFIX_LEN (sizeof(OVERRIDE_ANCHOR_SID_PREFIX) -1 )
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březinastatic void ipa_subdomain_account_got_override(struct tevent_req *subreq)
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina{
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct tevent_req *req = tevent_req_callback_data(subreq,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct tevent_req);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct ipa_subdomain_account_state *state = tevent_req_data(req,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct ipa_subdomain_account_state);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina int dp_error = DP_ERR_FATAL;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina int ret;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina const char *anchor = NULL;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct be_acct_req *ar;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina ret = ipa_get_ad_override_recv(subreq, &dp_error, state,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina &state->override_attrs);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina talloc_zfree(subreq);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina if (ret != EOK) {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina DEBUG(SSSDBG_OP_FAILURE, "IPA override lookup failed: %d\n", ret);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina goto fail;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina }
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina if (state->override_attrs != NULL) {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina ret = sysdb_attrs_get_string(state->override_attrs,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina SYSDB_OVERRIDE_ANCHOR_UUID,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina &anchor);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina if (ret != EOK) {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina goto fail;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina }
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina if (anchor != NULL && strncmp(OVERRIDE_ANCHOR_SID_PREFIX, anchor,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina OVERRIDE_ANCHOR_SID_PREFIX_LEN) == 0) {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina ret = get_be_acct_req_for_sid(state,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina anchor + OVERRIDE_ANCHOR_SID_PREFIX_LEN,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina state->ar->domain,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina &ar);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina if (ret != EOK) {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina DEBUG(SSSDBG_OP_FAILURE, "get_be_acct_req_for_sid failed.\n");
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina goto fail;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina }
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina } else {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina DEBUG(SSSDBG_CRIT_FAILURE,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina "Unsupported override anchor type [%s].\n", anchor);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina ret = EINVAL;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina goto fail;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina }
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina } else {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina ar = state->ar;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina }
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina ret = ipa_subdomain_account_get_original_step(req, ar);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina if (ret != EOK) {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina DEBUG(SSSDBG_OP_FAILURE,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina "ipa_subdomain_account_get_original_step failed.\n");
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina goto fail;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina }
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina return;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březinafail:
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina state->dp_error = dp_error;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina tevent_req_error(req, ret);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina return;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina}
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březinastatic errno_t ipa_subdomain_account_get_original_step(struct tevent_req *req,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct be_acct_req *ar)
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina{
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct ipa_subdomain_account_state *state = tevent_req_data(req,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct ipa_subdomain_account_state);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct tevent_req *subreq;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina if (state->ipa_server_mode) {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina subreq = ipa_get_ad_acct_send(state, state->ev, state->ipa_ctx,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina state->be_req, state->override_attrs, ar);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina } else {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina subreq = ipa_get_subdom_acct_send(state, state->ev, state->ipa_ctx,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina state->override_attrs, ar);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina }
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina if (subreq == NULL) {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina DEBUG(SSSDBG_OP_FAILURE, "ipa_get_*_acct_send failed.\n");
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina return ENOMEM;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina }
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina tevent_req_set_callback(subreq, ipa_subdomain_account_done, req);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina return EOK;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina}
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březinastatic void ipa_subdomain_account_done(struct tevent_req *subreq)
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina{
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct tevent_req *req = tevent_req_callback_data(subreq,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct tevent_req);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct ipa_subdomain_account_state *state = tevent_req_data(req,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct ipa_subdomain_account_state);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina int dp_error = DP_ERR_FATAL;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina int ret;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina if (state->ipa_server_mode) {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina ret = ipa_get_ad_acct_recv(subreq, &dp_error);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina } else {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina ret = ipa_get_subdom_acct_recv(subreq, &dp_error);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina }
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina talloc_zfree(subreq);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina if (ret != EOK) {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina DEBUG(SSSDBG_OP_FAILURE, "ipa_get_*_acct request failed: %d\n", ret);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina state->dp_error = dp_error;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina tevent_req_error(req, ret);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina return;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina }
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina state->dp_error = DP_ERR_OK;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina tevent_req_done(req);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina return;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina}
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březinaerrno_t ipa_subdomain_account_recv(struct tevent_req *req, int *dp_error_out)
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina{
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct ipa_subdomain_account_state *state = tevent_req_data(req,
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina struct ipa_subdomain_account_state);
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina if (dp_error_out) {
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina *dp_error_out = state->dp_error;
a76f63544533f0404f7711a10c1a621c6045df17Pavel Březina }
TEVENT_REQ_RETURN_ON_ERROR(req);
return EOK;
}
struct ipa_get_subdom_acct {
struct tevent_context *ev;
struct ipa_id_ctx *ipa_ctx;
struct sdap_id_ctx *ctx;
struct sdap_id_op *op;
struct sysdb_ctx *sysdb;
struct sss_domain_info *domain;
struct sysdb_attrs *override_attrs;
int entry_type;
const char *filter;
int filter_type;
int dp_error;
};
static void ipa_get_subdom_acct_connected(struct tevent_req *subreq);
static void ipa_get_subdom_acct_done(struct tevent_req *subreq);
struct tevent_req *ipa_get_subdom_acct_send(TALLOC_CTX *memctx,
struct tevent_context *ev,
struct ipa_id_ctx *ipa_ctx,
struct sysdb_attrs *override_attrs,
struct be_acct_req *ar)
{
struct tevent_req *req;
struct ipa_get_subdom_acct *state;
struct tevent_req *subreq;
int ret;
req = tevent_req_create(memctx, &state, struct ipa_get_subdom_acct);
if (!req) return NULL;
state->ev = ev;
state->ipa_ctx = ipa_ctx;
state->ctx = ipa_ctx->sdap_id_ctx;
state->dp_error = DP_ERR_FATAL;
state->override_attrs = override_attrs;
state->op = sdap_id_op_create(state, state->ctx->conn->conn_cache);
if (!state->op) {
DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
ret = ENOMEM;
goto fail;
}
state->domain = find_domain_by_name(state->ctx->be->domain,
ar->domain, true);
if (state->domain == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "find_domain_by_name failed.\n");
ret = ENOMEM;
goto fail;
}
state->sysdb = state->domain->sysdb;
state->entry_type = (ar->entry_type & BE_REQ_TYPE_MASK);
state->filter = ar->filter_value;
state->filter_type = ar->filter_type;
switch (state->entry_type) {
case BE_REQ_USER:
case BE_REQ_GROUP:
case BE_REQ_BY_SECID:
case BE_REQ_USER_AND_GROUP:
ret = EOK;
break;
case BE_REQ_INITGROUPS:
ret = ENOTSUP;
DEBUG(SSSDBG_TRACE_FUNC, "Initgroups requests are not handled " \
"by the IPA provider but are resolved " \
"by the responder directly from the " \
"cache.\n");
break;
default:
ret = EINVAL;
DEBUG(SSSDBG_OP_FAILURE, "Invalid sub-domain request type.\n");
}
if (ret != EOK) goto fail;
subreq = sdap_id_op_connect_send(state->op, state, &ret);
if (!subreq) {
goto fail;
}
tevent_req_set_callback(subreq, ipa_get_subdom_acct_connected, req);
return req;
fail:
tevent_req_error(req, ret);
tevent_req_post(req, ev);
return req;
}
static void ipa_get_subdom_acct_connected(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
struct ipa_get_subdom_acct *state = tevent_req_data(req,
struct ipa_get_subdom_acct);
int dp_error = DP_ERR_FATAL;
int ret;
char *endptr;
struct req_input *req_input;
ret = sdap_id_op_connect_recv(subreq, &dp_error);
talloc_zfree(subreq);
if (ret != EOK) {
state->dp_error = dp_error;
tevent_req_error(req, ret);
return;
}
req_input = talloc(state, struct req_input);
if (req_input == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "talloc failed.\n");
tevent_req_error(req, ENOMEM);
return;
}
switch (state->filter_type) {
case BE_FILTER_NAME:
req_input->type = REQ_INP_NAME;
req_input->inp.name = talloc_strdup(req_input, state->filter);
if (req_input->inp.name == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
tevent_req_error(req, ENOMEM);
return;
}
break;
case BE_FILTER_IDNUM:
req_input->type = REQ_INP_ID;
req_input->inp.id = strtouint32(state->filter, &endptr, 10);
if (errno || *endptr || (state->filter == endptr)) {
tevent_req_error(req, errno ? errno : EINVAL);
return;
}
break;
case BE_FILTER_SECID:
req_input->type = REQ_INP_SECID;
req_input->inp.secid = talloc_strdup(req_input, state->filter);
if (req_input->inp.secid == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
tevent_req_error(req, ENOMEM);
return;
}
break;
default:
DEBUG(SSSDBG_OP_FAILURE, "Invalid sub-domain filter type.\n");
state->dp_error = dp_error;
tevent_req_error(req, EINVAL);
return;
}
subreq = ipa_s2n_get_acct_info_send(state,
state->ev,
state->ipa_ctx,
state->ctx->opts,
state->domain,
state->override_attrs,
sdap_id_op_handle(state->op),
state->entry_type,
req_input);
if (!subreq) {
tevent_req_error(req, ENOMEM);
return;
}
tevent_req_set_callback(subreq, ipa_get_subdom_acct_done, req);
return;
}
static void ipa_get_subdom_acct_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
struct ipa_get_subdom_acct *state = tevent_req_data(req,
struct ipa_get_subdom_acct);
int dp_error = DP_ERR_FATAL;
int ret;
ret = ipa_s2n_get_acct_info_recv(subreq);
talloc_zfree(subreq);
ret = sdap_id_op_done(state->op, ret, &dp_error);
if (dp_error == DP_ERR_OK && ret != EOK) {
/* retry */
subreq = sdap_id_op_connect_send(state->op, state, &ret);
if (!subreq) {
tevent_req_error(req, ret);
return;
}
tevent_req_set_callback(subreq, ipa_get_subdom_acct_connected, req);
return;
}
if (ret && ret != ENOENT) {
state->dp_error = dp_error;
tevent_req_error(req, ret);
return;
}
/* FIXME: do we need some special handling of ENOENT */
state->dp_error = DP_ERR_OK;
tevent_req_done(req);
}
int ipa_get_subdom_acct_recv(struct tevent_req *req, int *dp_error_out)
{
struct ipa_get_subdom_acct *state = tevent_req_data(req,
struct ipa_get_subdom_acct);
if (dp_error_out) {
*dp_error_out = state->dp_error;
}
TEVENT_REQ_RETURN_ON_ERROR(req);
return EOK;
}
/* IPA lookup for server mode. Directly to AD. */
struct ipa_get_ad_acct_state {
int dp_error;
struct tevent_context *ev;
struct ipa_id_ctx *ipa_ctx;
struct be_req *be_req;
struct be_acct_req *ar;
struct sss_domain_info *user_dom;
char *object_sid;
struct sysdb_attrs *override_attrs;
struct ldb_message *obj_msg;
};
static void ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq);
static void ipa_get_ad_override_done(struct tevent_req *subreq);
static errno_t ipa_get_ad_apply_override_step(struct tevent_req *req);
static void ipa_get_ad_acct_done(struct tevent_req *subreq);
static struct ad_id_ctx *ipa_get_ad_id_ctx(struct ipa_id_ctx *ipa_ctx,
struct sss_domain_info *dom);
struct tevent_req *
ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct ipa_id_ctx *ipa_ctx,
struct be_req *be_req,
struct sysdb_attrs *override_attrs,
struct be_acct_req *ar)
{
errno_t ret;
struct tevent_req *req;
struct tevent_req *subreq;
struct ipa_get_ad_acct_state *state;
struct sdap_domain *sdom;
struct sdap_id_conn_ctx **clist;
struct sdap_id_ctx *sdap_id_ctx;;
struct ad_id_ctx *ad_id_ctx;
req = tevent_req_create(mem_ctx, &state, struct ipa_get_ad_acct_state);
if (req == NULL) return NULL;
state->dp_error = -1;
state->ev = ev;
state->ipa_ctx = ipa_ctx;
state->be_req = be_req;
state->ar = ar;
state->obj_msg = NULL;
state->override_attrs = override_attrs;
/* This can only be a subdomain request, verify subdomain */
state->user_dom = find_domain_by_name(ipa_ctx->sdap_id_ctx->be->domain,
ar->domain, true);
if (state->user_dom == NULL) {
ret = EINVAL;
goto fail;
}
/* Let's see if this subdomain has a ad_id_ctx */
ad_id_ctx = ipa_get_ad_id_ctx(ipa_ctx, state->user_dom);
if (ad_id_ctx == NULL) {
ret = EINVAL;
goto fail;
}
sdap_id_ctx = ad_id_ctx->sdap_id_ctx;
/* We read users and groups from GC. From groups, we may switch to
* using LDAP connection in the group request itself, but in order
* to resolve Universal group memberships, we also need the GC
* connection
*/
switch (state->ar->entry_type & BE_REQ_TYPE_MASK) {
case BE_REQ_INITGROUPS:
case BE_REQ_GROUP:
clist = ad_gc_conn_list(req, ad_id_ctx, state->user_dom);
if (clist == NULL) {
ret = ENOMEM;
goto fail;
}
break;
default:
clist = talloc_zero_array(req, struct sdap_id_conn_ctx *, 2);
if (clist == NULL) {
ret = ENOMEM;
goto fail;
}
clist[0] = ad_id_ctx->ldap_ctx;
clist[1] = NULL;
}
/* Now we already need ad_id_ctx in particular sdap_id_conn_ctx */
sdom = sdap_domain_get(sdap_id_ctx->opts, state->user_dom);
if (sdom == NULL) {
ret = EIO;
goto fail;
}
subreq = ad_handle_acct_info_send(req, be_req, ar, sdap_id_ctx,
ad_id_ctx->ad_options, sdom, clist);
if (subreq == NULL) {
ret = ENOMEM;
goto fail;
}
tevent_req_set_callback(subreq, ipa_get_ad_acct_ad_part_done, req);
return req;
fail:
state->dp_error = DP_ERR_FATAL;
tevent_req_error(req, ret);
tevent_req_post(req, ev);
return req;
}
static struct ad_id_ctx *
ipa_get_ad_id_ctx(struct ipa_id_ctx *ipa_ctx,
struct sss_domain_info *dom)
{
struct ipa_ad_server_ctx *iter;
DLIST_FOR_EACH(iter, ipa_ctx->server_mode->trusts) {
if (iter->dom == dom) break;
}
return (iter) ? iter->ad_id_ctx : NULL;
}
static errno_t
get_subdomain_homedir_of_user(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
const char *fqname, uint32_t uid,
const char **_homedir)
{
errno_t ret;
const char *name;
const char *homedir;
TALLOC_CTX *tmp_ctx;
struct sss_nss_homedir_ctx homedir_ctx;
tmp_ctx = talloc_new(mem_ctx);
if (tmp_ctx == NULL) {
ret = ENOMEM;
goto done;
}
ZERO_STRUCT(homedir_ctx);
homedir_ctx.uid = uid;
homedir_ctx.domain = dom->name;
homedir_ctx.flatname = dom->flat_name;
homedir_ctx.config_homedir_substr = dom->homedir_substr;
ret = sss_parse_name_const(tmp_ctx, dom->names, fqname,
NULL, &name);
if (ret != EOK) {
goto done;
}
/* To be compatible with the old winbind based user lookups and IPA
* clients the user name in the home directory path will be lower-case. */
homedir_ctx.username = sss_tc_utf8_str_tolower(tmp_ctx, name);
if (homedir_ctx.username == NULL) {
ret = ENOMEM;
goto done;
}
homedir = expand_homedir_template(tmp_ctx, dom->subdomain_homedir,
&homedir_ctx);
if (homedir == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "expand_homedir_template failed\n");
ret = ENOMEM;
goto done;
}
if (_homedir == NULL) {
ret = EINVAL;
goto done;
}
*_homedir = talloc_steal(mem_ctx, homedir);
done:
talloc_free(tmp_ctx);
return ret;
}
static errno_t
store_homedir_of_user(struct sss_domain_info *domain,
const char *fqname, const char *homedir)
{
errno_t ret;
errno_t sret;
TALLOC_CTX *tmp_ctx;
bool in_transaction = false;
struct sysdb_attrs *attrs;
struct sysdb_ctx *sysdb = domain->sysdb;
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
ret = ENOMEM;
goto done;
}
attrs = sysdb_new_attrs(tmp_ctx);
if (attrs == NULL) {
ret = ENOMEM;
goto done;
}
ret = sysdb_attrs_add_string(attrs, SYSDB_HOMEDIR, homedir);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE, "Error setting homedir: [%s]\n",
strerror(ret));
goto done;
}
ret = sysdb_transaction_start(sysdb);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
goto done;
}
in_transaction = true;
ret = sysdb_set_user_attr(domain, fqname, attrs, SYSDB_MOD_REP);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Failed to update homedir information!\n");
goto done;
}
ret = sysdb_transaction_commit(sysdb);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Cannot commit sysdb transaction [%d]: %s.\n",
ret, strerror(ret));
goto done;
}
in_transaction = false;
done:
if (in_transaction) {
sret = sysdb_transaction_cancel(sysdb);
if (sret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction.\n");
}
}
talloc_free(tmp_ctx);
return ret;
}
static errno_t
apply_subdomain_homedir(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
struct ldb_message *msg)
{
errno_t ret;
uint32_t uid;
const char *fqname;
const char *homedir = NULL;
struct ldb_message_element *msg_el = NULL;
size_t c;
msg_el = ldb_msg_find_element(msg, SYSDB_OBJECTCLASS);
if (msg_el == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_find_element failed.\n");
ret = ENOENT;
goto done;
}
for (c = 0; c < msg_el->num_values; c++) {
if (strncmp(SYSDB_USER_CLASS, (const char *)msg_el->values[c].data,
msg_el->values[c].length) == 0) {
break;
}
}
if (c == msg_el->num_values) {
DEBUG(SSSDBG_TRACE_ALL,
"User objectclass not found, object is not a user.\n");
ret = ENOENT;
goto done;
}
/*
* Homedir is always overriden by subdomain_homedir even if it was
* explicitly set by user.
*/
fqname = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
if (fqname == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Missing user name.\n");
ret = EINVAL;
goto done;
}
uid = ldb_msg_find_attr_as_uint64(msg, SYSDB_UIDNUM, 0);
if (uid == 0) {
DEBUG(SSSDBG_OP_FAILURE, "UID for user [%s] is not known.\n",
fqname);
ret = ENOENT;
goto done;
}
ret = get_subdomain_homedir_of_user(mem_ctx, dom, fqname, uid, &homedir);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"get_subdomain_homedir_of_user failed: [%d]: [%s]\n",
ret, sss_strerror(ret));
goto done;
}
ret = store_homedir_of_user(dom, fqname, homedir);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"store_homedir_of_user failed: [%d]: [%s]\n",
ret, sss_strerror(ret));
goto done;
}
done:
return ret;
}
static errno_t get_object_from_cache(TALLOC_CTX *mem_ctx,
struct sss_domain_info *dom,
struct be_acct_req *ar,
struct ldb_message **_msg)
{
errno_t ret;
uint32_t id;
struct ldb_message *msg = NULL;
struct ldb_result *res = NULL;
const char *attrs[] = { SYSDB_NAME,
SYSDB_UIDNUM,
SYSDB_SID_STR,
SYSDB_OBJECTCLASS,
NULL };
char *name;
if (ar->filter_type == BE_FILTER_SECID) {
ret = sysdb_search_object_by_sid(mem_ctx, dom, ar->filter_value, attrs,
&res);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Failed to make request to our cache: [%d]: [%s]\n",
ret, sss_strerror(ret));
goto done;
}
*_msg = res->msgs[0];
ret = EOK;
goto done;
}
if (ar->filter_type == BE_FILTER_IDNUM) {
errno = 0;
id = strtouint32(ar->filter_value, NULL, 10);
if (errno != 0) {
ret = errno;
DEBUG(SSSDBG_OP_FAILURE, "strtouint32 failed.\n");
goto done;
}
switch (ar->entry_type & BE_REQ_TYPE_MASK) {
case BE_REQ_GROUP:
ret = sysdb_search_group_by_gid(mem_ctx, dom, id, attrs, &msg);
break;
case BE_REQ_INITGROUPS:
case BE_REQ_USER:
case BE_REQ_USER_AND_GROUP:
ret = sysdb_search_user_by_uid(mem_ctx, dom, id, attrs, &msg);
if (ret == ENOENT && (ar->entry_type & BE_REQ_TYPE_MASK)
== BE_REQ_USER_AND_GROUP) {
ret = sysdb_search_group_by_gid(mem_ctx, dom, id, attrs, &msg);
}
break;
default:
DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected entry type [%d].\n",
(ar->entry_type & BE_REQ_TYPE_MASK));
ret = EINVAL;
goto done;
}
} else if (ar->filter_type == BE_FILTER_NAME) {
name = sss_get_domain_name(mem_ctx, ar->filter_value, dom);
if (name == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "sss_get_domain_name failed\n");
ret = ENOMEM;
goto done;
}
switch (ar->entry_type & BE_REQ_TYPE_MASK) {
case BE_REQ_GROUP:
ret = sysdb_search_group_by_name(mem_ctx, dom, name, attrs, &msg);
break;
case BE_REQ_INITGROUPS:
case BE_REQ_USER:
case BE_REQ_USER_AND_GROUP:
ret = sysdb_search_user_by_name(mem_ctx, dom, name, attrs, &msg);
if (ret == ENOENT && (ar->entry_type & BE_REQ_TYPE_MASK)
== BE_REQ_USER_AND_GROUP) {
ret = sysdb_search_group_by_name(mem_ctx, dom, name,
attrs, &msg);
}
break;
default:
DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected entry type [%d].\n",
(ar->entry_type & BE_REQ_TYPE_MASK));
ret = EINVAL;
goto done;
}
} else {
DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected filter type.\n");
ret = EINVAL;
goto done;
}
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Failed to make request to our cache: [%d]: [%s]\n",
ret, sss_strerror(ret));
goto done;
}
*_msg = msg;
ret = EOK;
done:
return ret;
}
static void
ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
struct ipa_get_ad_acct_state *state = tevent_req_data(req,
struct ipa_get_ad_acct_state);
errno_t ret;
const char *sid;
struct be_acct_req *ar;
ret = ad_handle_acct_info_recv(subreq, &state->dp_error, NULL);
talloc_zfree(subreq);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "AD lookup failed: %d\n", ret);
tevent_req_error(req, ret);
return;
}
ret = get_object_from_cache(state, state->user_dom, state->ar,
&state->obj_msg);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "get_object_from_cache failed.\n");
goto fail;
}
ret = apply_subdomain_homedir(state, state->user_dom,
state->obj_msg);
if (ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_OP_FAILURE,
"apply_subdomain_homedir failed: [%d]: [%s].\n",
ret, sss_strerror(ret));
goto fail;
}
if (state->override_attrs == NULL) {
sid = ldb_msg_find_attr_as_string(state->obj_msg, SYSDB_SID_STR, NULL);
if (sid == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find a SID.\n");
ret = EINVAL;
goto fail;
}
state->object_sid = talloc_strdup(state, sid);
if (state->object_sid == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
ret = ENOMEM;
goto fail;
}
ret = get_be_acct_req_for_sid(state, state->object_sid,
state->user_dom->name, &ar);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "get_be_acct_req_for_sid failed.\n");
goto fail;
}
subreq = ipa_get_ad_override_send(state, state->ev,
state->ipa_ctx->sdap_id_ctx,
state->ipa_ctx->ipa_options,
state->ipa_ctx->server_mode->realm,
state->ipa_ctx->view_name,
ar);
if (subreq == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_override_send failed.\n");
ret = ENOMEM;
goto fail;
}
tevent_req_set_callback(subreq, ipa_get_ad_override_done, req);
} else {
ret = ipa_get_ad_apply_override_step(req);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"ipa_get_ad_apply_override_step failed.\n");
goto fail;
}
}
return;
fail:
state->dp_error = DP_ERR_FATAL;
tevent_req_error(req, ret);
return;
}
static void
ipa_get_ad_override_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
struct ipa_get_ad_acct_state *state = tevent_req_data(req,
struct ipa_get_ad_acct_state);
errno_t ret;
ret = ipa_get_ad_override_recv(subreq, &state->dp_error, state,
&state->override_attrs);
talloc_zfree(subreq);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "IPA override lookup failed: %d\n", ret);
tevent_req_error(req, ret);
return;
}
ret = ipa_get_ad_apply_override_step(req);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_apply_override_step failed.\n");
goto fail;
}
return;
fail:
state->dp_error = DP_ERR_FATAL;
tevent_req_error(req, ret);
return;
}
static errno_t ipa_get_ad_apply_override_step(struct tevent_req *req)
{
struct ipa_get_ad_acct_state *state = tevent_req_data(req,
struct ipa_get_ad_acct_state);
errno_t ret;
struct tevent_req *subreq;
if (state->override_attrs != NULL) {
/* We are in ipa-server-mode, so the view is the default view by
* definition. */
ret = sysdb_apply_default_override(state->user_dom,
state->override_attrs,
state->obj_msg->dn);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "sysdb_apply_default_override failed.\n");
return ret;
}
}
if ((state->ar->entry_type & BE_REQ_TYPE_MASK) != BE_REQ_INITGROUPS) {
tevent_req_done(req);
return EOK;
}
/* For initgroups request we have to check IPA group memberships of AD
* users. */
subreq = ipa_get_ad_memberships_send(state, state->ev, state->ar,
state->ipa_ctx->server_mode,
state->user_dom,
state->ipa_ctx->sdap_id_ctx,
state->ipa_ctx->server_mode->realm);
if (subreq == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ad_memberships_send failed.\n");
return ENOMEM;
}
tevent_req_set_callback(subreq, ipa_get_ad_acct_done, req);
return EOK;
}
static void
ipa_get_ad_acct_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
struct ipa_get_ad_acct_state *state = tevent_req_data(req,
struct ipa_get_ad_acct_state);
errno_t ret;
ret = ipa_get_ad_memberships_recv(subreq, &state->dp_error);
talloc_zfree(subreq);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "IPA external groups lookup failed: %d\n",
ret);
tevent_req_error(req, ret);
return;
}
tevent_req_done(req);
}
errno_t
ipa_get_ad_acct_recv(struct tevent_req *req, int *dp_error_out)
{
struct ipa_get_ad_acct_state *state = tevent_req_data(req,
struct ipa_get_ad_acct_state);
if (dp_error_out) {
*dp_error_out = state->dp_error;
}
TEVENT_REQ_RETURN_ON_ERROR(req);
return EOK;
}