summaryrefslogtreecommitdiffstats
path: root/src/providers/ipa/ipa_access.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/providers/ipa/ipa_access.c')
-rw-r--r--src/providers/ipa/ipa_access.c787
1 files changed, 787 insertions, 0 deletions
diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c
new file mode 100644
index 0000000..205ebe3
--- /dev/null
+++ b/src/providers/ipa/ipa_access.c
@@ -0,0 +1,787 @@
+/*
+ SSSD
+
+ IPA Backend Module -- Access control
+
+ Authors:
+ Sumit Bose <sbose@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 <security/pam_modules.h>
+
+#include "util/util.h"
+#include "providers/ldap/sdap_async.h"
+#include "providers/ldap/sdap_access.h"
+#include "providers/ipa/ipa_common.h"
+#include "providers/ipa/ipa_access.h"
+#include "providers/ipa/ipa_hosts.h"
+#include "providers/ipa/ipa_hbac_private.h"
+#include "providers/ipa/ipa_hbac_rules.h"
+#include "providers/ipa/ipa_rules_common.h"
+
+/* External logging function for HBAC. */
+void hbac_debug_messages(const char *file, int line,
+ const char *function,
+ enum hbac_debug_level level,
+ const char *fmt, ...)
+{
+ int loglevel;
+ va_list ap;
+
+ switch(level) {
+ case HBAC_DBG_FATAL:
+ loglevel = SSSDBG_FATAL_FAILURE;
+ break;
+ case HBAC_DBG_ERROR:
+ loglevel = SSSDBG_OP_FAILURE;
+ break;
+ case HBAC_DBG_WARNING:
+ loglevel = SSSDBG_MINOR_FAILURE;
+ break;
+ case HBAC_DBG_INFO:
+ loglevel = SSSDBG_CONF_SETTINGS;
+ break;
+ case HBAC_DBG_TRACE:
+ loglevel = SSSDBG_TRACE_INTERNAL;
+ break;
+ default:
+ loglevel = SSSDBG_UNRESOLVED;
+ break;
+ }
+
+ va_start(ap, fmt);
+ sss_vdebug_fn(file, line, function, loglevel, 0, fmt, ap);
+ va_end(ap);
+}
+
+enum hbac_result {
+ HBAC_ALLOW = 1,
+ HBAC_DENY,
+ HBAC_NOT_APPLICABLE
+};
+
+enum check_result {
+ RULE_APPLICABLE = 0,
+ RULE_NOT_APPLICABLE,
+ RULE_ERROR
+};
+
+struct ipa_fetch_hbac_state {
+ struct tevent_context *ev;
+ struct be_ctx *be_ctx;
+ struct sdap_id_ctx *sdap_ctx;
+ struct ipa_access_ctx *access_ctx;
+ struct sdap_id_op *sdap_op;
+ struct dp_option *ipa_options;
+
+ struct sdap_search_base **search_bases;
+
+ /* Hosts */
+ struct ipa_common_entries *hosts;
+ struct sysdb_attrs *ipa_host;
+
+ /* Rules */
+ struct ipa_common_entries *rules;
+
+ /* Services */
+ struct ipa_common_entries *services;
+};
+
+static errno_t ipa_fetch_hbac_retry(struct tevent_req *req);
+static void ipa_fetch_hbac_connect_done(struct tevent_req *subreq);
+static errno_t ipa_fetch_hbac_hostinfo(struct tevent_req *req);
+static void ipa_fetch_hbac_hostinfo_done(struct tevent_req *subreq);
+static void ipa_fetch_hbac_services_done(struct tevent_req *subreq);
+static void ipa_fetch_hbac_rules_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+ipa_fetch_hbac_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct be_ctx *be_ctx,
+ struct ipa_access_ctx *access_ctx)
+{
+ struct ipa_fetch_hbac_state *state;
+ struct tevent_req *req;
+ time_t now, refresh_interval;
+ bool offline;
+ errno_t ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct ipa_fetch_hbac_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->be_ctx = be_ctx;
+ state->access_ctx = access_ctx;
+ state->sdap_ctx = access_ctx->sdap_ctx;
+ state->ipa_options = access_ctx->ipa_options;
+ state->search_bases = access_ctx->hbac_search_bases;
+ state->hosts = talloc_zero(state, struct ipa_common_entries);
+ if (state->hosts == NULL) {
+ ret = ENOMEM;
+ goto immediately;
+ }
+ state->services = talloc_zero(state, struct ipa_common_entries);
+ if (state->hosts == NULL) {
+ ret = ENOMEM;
+ goto immediately;
+ }
+ state->rules = talloc_zero(state, struct ipa_common_entries);
+ if (state->rules == NULL) {
+ ret = ENOMEM;
+ goto immediately;
+ }
+
+ if (state->search_bases == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "No HBAC search base found.\n");
+ ret = EINVAL;
+ goto immediately;
+ }
+
+ state->sdap_op = sdap_id_op_create(state, state->sdap_ctx->conn->conn_cache);
+ if (state->sdap_op == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create() failed\n");
+ ret = ENOMEM;
+ goto immediately;
+ }
+
+ offline = be_is_offline(be_ctx);
+ DEBUG(SSSDBG_TRACE_ALL, "Connection status is [%s].\n",
+ offline ? "offline" : "online");
+
+ refresh_interval = dp_opt_get_int(state->ipa_options, IPA_HBAC_REFRESH);
+ now = time(NULL);
+
+ if (offline || now < access_ctx->last_update + refresh_interval) {
+ DEBUG(SSSDBG_TRACE_FUNC, "Performing cached HBAC evaluation\n");
+ ret = EOK;
+ goto immediately;
+ }
+
+ ret = ipa_fetch_hbac_retry(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 errno_t ipa_fetch_hbac_retry(struct tevent_req *req)
+{
+ struct ipa_fetch_hbac_state *state;
+ struct tevent_req *subreq;
+ int ret;
+
+ state = tevent_req_data(req, struct ipa_fetch_hbac_state);
+
+ subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
+ if (subreq == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "sdap_id_op_connect_send() failed: "
+ "%d(%s)\n", ret, strerror(ret));
+ return ret;
+ }
+
+ tevent_req_set_callback(subreq, ipa_fetch_hbac_connect_done, req);
+
+ return EAGAIN;
+}
+
+static void ipa_fetch_hbac_connect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = NULL;
+ int dp_error;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+
+ ret = sdap_id_op_connect_recv(subreq, &dp_error);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ if (dp_error == DP_ERR_OFFLINE) {
+ ret = EOK;
+ goto done;
+ }
+
+ ret = ipa_fetch_hbac_hostinfo(req);
+ if (ret == EAGAIN) {
+ return;
+ }
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static errno_t ipa_fetch_hbac_hostinfo(struct tevent_req *req)
+{
+ struct ipa_fetch_hbac_state *state;
+ struct tevent_req *subreq;
+ const char *hostname;
+ bool srchost;
+
+ state = tevent_req_data(req, struct ipa_fetch_hbac_state);
+
+ srchost = dp_opt_get_bool(state->ipa_options, IPA_HBAC_SUPPORT_SRCHOST);
+ if (srchost) {
+ /* Support srchost
+ * -> we don't want any particular host,
+ * we want all hosts
+ */
+ hostname = NULL;
+
+ /* THIS FEATURE IS DEPRECATED */
+ DEBUG(SSSDBG_MINOR_FAILURE, "WARNING: Using deprecated option "
+ "ipa_hbac_support_srchost.\n");
+ sss_log(SSS_LOG_NOTICE, "WARNING: Using deprecated option "
+ "ipa_hbac_support_srchost.\n");
+ } else {
+ hostname = dp_opt_get_string(state->ipa_options, IPA_HOSTNAME);
+ }
+
+ subreq = ipa_host_info_send(state, state->ev,
+ sdap_id_op_handle(state->sdap_op),
+ state->sdap_ctx->opts, hostname,
+ state->access_ctx->host_map,
+ state->access_ctx->hostgroup_map,
+ state->access_ctx->host_search_bases);
+ if (subreq == NULL) {
+ return ENOMEM;
+ }
+
+ tevent_req_set_callback(subreq, ipa_fetch_hbac_hostinfo_done, req);
+
+ return EAGAIN;
+}
+
+static void ipa_fetch_hbac_hostinfo_done(struct tevent_req *subreq)
+{
+ struct ipa_fetch_hbac_state *state = NULL;
+ struct tevent_req *req = NULL;
+ errno_t ret;
+ int dp_error;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_fetch_hbac_state);
+
+ ret = ipa_host_info_recv(subreq, state,
+ &state->hosts->entry_count,
+ &state->hosts->entries,
+ &state->hosts->group_count,
+ &state->hosts->groups);
+ state->hosts->entry_subdir = HBAC_HOSTS_SUBDIR;
+ state->hosts->group_subdir = HBAC_HOSTGROUPS_SUBDIR;
+ talloc_zfree(subreq);
+
+ if (ret != EOK) {
+ /* Only call sdap_id_op_done in case of an error to trigger a
+ * failover. In general changing the tevent_req layout would be better
+ * so that all searches are in another sub-request so that we can
+ * error out at any step and the parent request can call
+ * sdap_id_op_done just once. */
+ ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
+ if (dp_error == DP_ERR_OK && ret != EOK) {
+ /* retry */
+ ret = ipa_fetch_hbac_retry(req);
+ if (ret != EAGAIN) {
+ goto done;
+ }
+ return;
+ }
+ goto done;
+ }
+
+ subreq = ipa_hbac_service_info_send(state, state->ev,
+ sdap_id_op_handle(state->sdap_op),
+ state->sdap_ctx->opts,
+ state->search_bases);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tevent_req_set_callback(subreq, ipa_fetch_hbac_services_done, req);
+
+ return;
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static void ipa_fetch_hbac_services_done(struct tevent_req *subreq)
+{
+ struct ipa_fetch_hbac_state *state;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_fetch_hbac_state);
+
+ ret = ipa_hbac_service_info_recv(subreq, state,
+ &state->services->entry_count,
+ &state->services->entries,
+ &state->services->group_count,
+ &state->services->groups);
+ state->services->entry_subdir = HBAC_SERVICES_SUBDIR;
+ state->services->group_subdir = HBAC_SERVICEGROUPS_SUBDIR;
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ /* Get the ipa_host attrs */
+ ret = ipa_get_host_attrs(state->ipa_options,
+ state->hosts->entry_count,
+ state->hosts->entries,
+ &state->ipa_host);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Could not locate IPA host.\n");
+ goto done;
+ }
+
+ subreq = ipa_hbac_rule_info_send(state, state->ev,
+ sdap_id_op_handle(state->sdap_op),
+ state->sdap_ctx->opts,
+ state->search_bases,
+ state->ipa_host);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tevent_req_set_callback(subreq, ipa_fetch_hbac_rules_done, req);
+
+ return;
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static void ipa_fetch_hbac_rules_done(struct tevent_req *subreq)
+{
+ struct ipa_fetch_hbac_state *state = NULL;
+ struct tevent_req *req = NULL;
+ int dp_error;
+ errno_t ret;
+ bool found;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_fetch_hbac_state);
+
+ ret = ipa_hbac_rule_info_recv(subreq, state,
+ &state->rules->entry_count,
+ &state->rules->entries);
+ state->rules->entry_subdir = HBAC_RULES_SUBDIR;
+ talloc_zfree(subreq);
+ if (ret == ENOENT) {
+ /* Set ret to EOK so we can safely call sdap_id_op_done. */
+ found = false;
+ ret = EOK;
+ } else if (ret == EOK) {
+ found = true;
+ } else {
+ goto done;
+ }
+
+ ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
+ if (dp_error == DP_ERR_OK && ret != EOK) {
+ /* retry */
+ ret = ipa_fetch_hbac_retry(req);
+ if (ret != EAGAIN) {
+ tevent_req_error(req, ret);
+ }
+ return;
+ } else if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ if (found == false) {
+ /* No rules were found that apply to this host. */
+ ret = ipa_common_purge_rules(state->be_ctx->domain,
+ HBAC_RULES_SUBDIR);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to remove HBAC rules\n");
+ goto done;
+ }
+
+ ret = ENOENT;
+ goto done;
+ }
+
+ ret = ipa_common_save_rules(state->be_ctx->domain,
+ state->hosts, state->services, state->rules,
+ &state->access_ctx->last_update);
+
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to save HBAC rules\n");
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static errno_t ipa_fetch_hbac_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
+}
+
+errno_t ipa_hbac_evaluate_rules(struct be_ctx *be_ctx,
+ struct dp_option *ipa_options,
+ struct pam_data *pd)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct hbac_ctx hbac_ctx;
+ struct hbac_rule **hbac_rules;
+ struct hbac_eval_req *eval_req;
+ enum hbac_eval_result result;
+ struct hbac_info *info = NULL;
+ const char **attrs_get_cached_rules;
+ errno_t ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ hbac_ctx.be_ctx = be_ctx;
+ hbac_ctx.ipa_options = ipa_options;
+ hbac_ctx.pd = pd;
+
+ /* Get HBAC rules from the sysdb */
+ attrs_get_cached_rules = hbac_get_attrs_to_get_cached_rules(tmp_ctx);
+ if (attrs_get_cached_rules == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "hbac_get_attrs_to_get_cached_rules() failed\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ ret = ipa_common_get_cached_rules(tmp_ctx, be_ctx->domain,
+ IPA_HBAC_RULE, HBAC_RULES_SUBDIR,
+ attrs_get_cached_rules,
+ &hbac_ctx.rule_count, &hbac_ctx.rules);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Could not retrieve rules from the cache\n");
+ goto done;
+ }
+
+ ret = hbac_ctx_to_rules(tmp_ctx, &hbac_ctx, &hbac_rules, &eval_req);
+ if (ret == EPERM) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "DENY rules detected. Denying access to all users\n");
+ ret = ERR_ACCESS_DENIED;
+ goto done;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Could not construct HBAC rules\n");
+ goto done;
+ }
+
+ hbac_enable_debug(hbac_debug_messages);
+
+ result = hbac_evaluate(hbac_rules, eval_req, &info);
+ if (result == HBAC_EVAL_ALLOW) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "Access granted by HBAC rule [%s]\n",
+ info->rule_name);
+ ret = EOK;
+ goto done;
+ } else if (result == HBAC_EVAL_ERROR) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Error [%s] occurred in rule [%s]\n",
+ hbac_error_string(info->code), info->rule_name);
+ ret = EIO;
+ goto done;
+ } else if (result == HBAC_EVAL_OOM) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Insufficient memory\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ DEBUG(SSSDBG_MINOR_FAILURE, "Access denied by HBAC rules\n");
+ ret = ERR_ACCESS_DENIED;
+
+done:
+ hbac_free_info(info);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+struct ipa_pam_access_handler_state {
+ struct tevent_context *ev;
+ struct be_ctx *be_ctx;
+ struct ipa_access_ctx *access_ctx;
+ struct pam_data *pd;
+};
+
+static void ipa_pam_access_handler_sdap_done(struct tevent_req *subreq);
+static void ipa_pam_access_handler_done(struct tevent_req *subreq);
+
+struct tevent_req *
+ipa_pam_access_handler_send(TALLOC_CTX *mem_ctx,
+ struct ipa_access_ctx *access_ctx,
+ struct pam_data *pd,
+ struct dp_req_params *params)
+{
+ struct ipa_pam_access_handler_state *state;
+ struct tevent_req *subreq;
+ struct tevent_req *req;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct ipa_pam_access_handler_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+ return NULL;
+ }
+
+ state->pd = pd;
+ state->ev = params->ev;
+ state->be_ctx = params->be_ctx;
+ state->access_ctx = access_ctx;
+
+ subreq = sdap_access_send(state, params->ev, params->be_ctx,
+ params->domain, access_ctx->sdap_access_ctx,
+ access_ctx->sdap_ctx->conn, pd);
+ if (subreq == NULL) {
+ state->pd->pam_status = PAM_SYSTEM_ERR;
+ goto immediately;
+ }
+
+ tevent_req_set_callback(subreq, ipa_pam_access_handler_sdap_done, req);
+
+ return req;
+
+immediately:
+ /* TODO For backward compatibility we always return EOK to DP now. */
+ tevent_req_done(req);
+ tevent_req_post(req, params->ev);
+
+ return req;
+}
+
+static void ipa_pam_access_handler_sdap_done(struct tevent_req *subreq)
+{
+ struct ipa_pam_access_handler_state *state;
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_pam_access_handler_state);
+
+ ret = sdap_access_recv(subreq);
+ talloc_free(subreq);
+ switch (ret) {
+ case EOK:
+ case ERR_PASSWORD_EXPIRED_WARN:
+ /* Account wasn't locked. Continue below to HBAC processing. */
+ state->pd->pam_status = PAM_SUCCESS;
+ break;
+ case ERR_PASSWORD_EXPIRED_RENEW:
+ state->pd->pam_status = PAM_NEW_AUTHTOK_REQD;
+ break;
+ case ERR_ACCESS_DENIED:
+ case ERR_PASSWORD_EXPIRED_REJECT:
+ /* Account was locked or password expired. */
+ state->pd->pam_status = PAM_PERM_DENIED;
+ goto done;
+ case ERR_ACCOUNT_EXPIRED:
+ state->pd->pam_status = PAM_ACCT_EXPIRED;
+ goto done;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, "Error retrieving access check result "
+ "[%d]: %s.\n", ret, sss_strerror(ret));
+ state->pd->pam_status = PAM_SYSTEM_ERR;
+ break;
+ }
+
+ subreq = ipa_fetch_hbac_send(state, state->ev, state->be_ctx,
+ state->access_ctx);
+ if (subreq == NULL) {
+ state->pd->pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+
+ /* The callback function will not overwrite pam_status in case of
+ * success. Because of that, pam_status must be set to the desired
+ * value in advance. */
+ tevent_req_set_callback(subreq, ipa_pam_access_handler_done, req);
+
+ return;
+
+done:
+ /* TODO For backward compatibility we always return EOK to DP now. */
+ tevent_req_done(req);
+}
+
+static void ipa_pam_access_handler_done(struct tevent_req *subreq)
+{
+ struct ipa_pam_access_handler_state *state;
+ struct tevent_req *req;
+ int preset_pam_status;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct ipa_pam_access_handler_state);
+
+ ret = ipa_fetch_hbac_recv(subreq);
+ talloc_free(subreq);
+
+ if (ret == ENOENT) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "No HBAC rules found, denying access\n");
+ state->pd->pam_status = PAM_PERM_DENIED;
+ goto done;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to fetch HBAC rules [%d]: %s\n",
+ ret, sss_strerror(ret));
+ state->pd->pam_status = PAM_SYSTEM_ERR;
+ goto done;
+ }
+
+ /* ipa_hbac_evaluate_rules() could overwrite state->pd->pam_status but
+ we don't want that. Save the previous value and set it back in case
+ of succcess. */
+ preset_pam_status = state->pd->pam_status;
+ ret = ipa_hbac_evaluate_rules(state->be_ctx,
+ state->access_ctx->ipa_options, state->pd);
+ if (ret == EOK) {
+ state->pd->pam_status = preset_pam_status;
+ } else if (ret == ERR_ACCESS_DENIED) {
+ state->pd->pam_status = PAM_PERM_DENIED;
+ } else {
+ state->pd->pam_status = PAM_SYSTEM_ERR;
+ }
+done:
+ /* TODO For backward compatibility we always return EOK to DP now. */
+ tevent_req_done(req);
+}
+
+errno_t
+ipa_pam_access_handler_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ struct pam_data **_data)
+{
+ struct ipa_pam_access_handler_state *state = NULL;
+
+ state = tevent_req_data(req, struct ipa_pam_access_handler_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *_data = talloc_steal(mem_ctx, state->pd);
+
+ return EOK;
+}
+
+struct ipa_refresh_access_rules_state {
+ int dummy;
+};
+
+static void ipa_refresh_access_rules_done(struct tevent_req *subreq);
+
+struct tevent_req *
+ipa_refresh_access_rules_send(TALLOC_CTX *mem_ctx,
+ struct ipa_access_ctx *access_ctx,
+ void *no_input_data,
+ struct dp_req_params *params)
+{
+ struct ipa_refresh_access_rules_state *state;
+ struct tevent_req *subreq;
+ struct tevent_req *req;
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Refreshing HBAC rules\n");
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct ipa_refresh_access_rules_state);
+ if (req == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n");
+ return NULL;
+ }
+
+ subreq = ipa_fetch_hbac_send(state, params->ev, params->be_ctx, access_ctx);
+ if (subreq == NULL) {
+ tevent_req_error(req, ENOMEM);
+ tevent_req_post(req, params->ev);
+ return req;
+ }
+
+ tevent_req_set_callback(subreq, ipa_refresh_access_rules_done, req);
+
+ return req;
+}
+
+static void ipa_refresh_access_rules_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req;
+ errno_t ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+
+ ret = ipa_fetch_hbac_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+ return;
+}
+
+errno_t ipa_refresh_access_rules_recv(TALLOC_CTX *mem_ctx,
+ struct tevent_req *req,
+ void **_no_output_data)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
+}