From f83830c835fe781eab99d6fb838c3624c0bbcc7d Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Mon, 6 Jun 2011 22:38:15 -0400
Subject: [PATCH 6/7] Add new HBAC lookup and evaluation routines

---
 Makefile.am                    |    3 +-
 src/providers/ipa/ipa_access.c |  454 +++++++++++++++++++++++++++++-----------
 src/providers/ipa/ipa_access.h |   17 ++
 3 files changed, 347 insertions(+), 127 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 5a18f8299cab2d62aac91526ad2ab0e566d54f37..1ce34f2872cdc2dfcb2dadd6d3e4eddba12af14b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -927,7 +927,8 @@ libsss_ipa_la_LIBADD = \
     $(DHASH_LIBS) \
     $(KEYUTILS_LIBS) \
     $(KRB5_LIBS) \
-    libsss_util.la
+    libsss_util.la \
+    libipa_hbac.la
 libsss_ipa_la_LDFLAGS = \
     -avoid-version \
     -module
diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c
index 51392bb496bbba034f92c657e4d6b1b22163668b..ee74dfd52cf1acc1e11eabcffab82bb673171a18 100644
--- a/src/providers/ipa/ipa_access.c
+++ b/src/providers/ipa/ipa_access.c
@@ -29,6 +29,8 @@
 #include "providers/ldap/sdap_async.h"
 #include "providers/ipa/ipa_common.h"
 #include "providers/ipa/ipa_access.h"
+#include "providers/ipa/ipa_hbac.h"
+#include "providers/ipa/ipa_hbac_private.h"
 
 static char *get_hbac_search_base(TALLOC_CTX *mem_ctx,
                                   struct dp_option *ipa_options)
@@ -56,21 +58,32 @@ static char *get_hbac_search_base(TALLOC_CTX *mem_ctx,
 
 static void ipa_access_reply(struct hbac_ctx *hbac_ctx, int pam_status)
 {
+    struct be_req *be_req = hbac_ctx->be_req;
+    struct pam_data *pd;
+    pd = talloc_get_type(be_req->req_data, struct pam_data);
+    pd->pam_status = pam_status;
 
-    return EOK;
+    /* destroy HBAC context now to release all used resources and LDAP connection */
+    talloc_zfree(hbac_ctx);
 
-not_applicable:
-    if (ret == RULE_NOT_APPLICABLE) {
-        *result = HBAC_NOT_APPLICABLE;
+    if (pam_status == PAM_SUCCESS || pam_status == PAM_PERM_DENIED) {
+        be_req->fn(be_req, DP_ERR_OK, pam_status, NULL);
     } else {
-        *result = HBAC_DENY;
+        be_req->fn(be_req, DP_ERR_FATAL, pam_status, NULL);
     }
-    return EOK;
 }
 
+enum hbac_result {
+    HBAC_ALLOW = 1,
+    HBAC_DENY,
+    HBAC_NOT_APPLICABLE
+};
 
-    return EOK;
-}
+enum check_result {
+    RULE_APPLICABLE = 0,
+    RULE_NOT_APPLICABLE,
+    RULE_ERROR
+};
 
 static int hbac_retry(struct hbac_ctx *hbac_ctx);
 static void hbac_connect_done(struct tevent_req *subreq);
@@ -78,6 +91,8 @@ static bool hbac_check_step_result(struct hbac_ctx *hbac_ctx, int ret);
 
 static int hbac_get_host_info_step(struct hbac_ctx *hbac_ctx);
 
+static void ipa_hbac_evaluate_rules(struct hbac_ctx *hbac_ctx);
+
 void ipa_access_handler(struct be_req *be_req)
 {
     struct pam_data *pd;
@@ -128,18 +143,36 @@ static int hbac_retry(struct hbac_ctx *hbac_ctx)
 {
     struct tevent_req *subreq;
     int ret;
+    bool offline;
 
-    if (hbac_ctx_is_offline(hbac_ctx)) {
-        return hbac_get_host_info_step(hbac_ctx);
-    }
+    offline = be_is_offline(hbac_ctx->be_req->be_ctx);
+    DEBUG(9, ("Connection status is [%s].\n", offline ? "offline" : "online"));
 
-    subreq = sdap_id_op_connect_send(hbac_ctx_sdap_id_op(hbac_ctx), hbac_ctx, &ret);
-    if (!subreq) {
-        DEBUG(1, ("sdap_id_op_connect_send failed: %d(%s).\n", ret, strerror(ret)));
-        return ret;
-    }
+    if (!offline) {
+        if (hbac_ctx->sdap_op == NULL) {
+            hbac_ctx->sdap_op = sdap_id_op_create(hbac_ctx,
+                                        hbac_ctx_sdap_id_ctx(hbac_ctx)->conn_cache);
+            if (hbac_ctx->sdap_op == NULL) {
+                DEBUG(1, ("sdap_id_op_create failed.\n"));
+                return EIO;
+            }
+        }
 
-    tevent_req_set_callback(subreq, hbac_connect_done, hbac_ctx);
+        subreq = sdap_id_op_connect_send(hbac_ctx_sdap_id_op(hbac_ctx), hbac_ctx, &ret);
+        if (!subreq) {
+            DEBUG(1, ("sdap_id_op_connect_send failed: %d(%s).\n", ret, strerror(ret)));
+            talloc_zfree(hbac_ctx->sdap_op);
+            return ret;
+        }
+
+        tevent_req_set_callback(subreq, hbac_connect_done, hbac_ctx);
+    } else {
+        /* Evaluate the rules based on what we have in the
+         * sysdb
+         */
+        ipa_hbac_evaluate_rules(hbac_ctx);
+        return EOK;
+    }
     return EOK;
 }
 
@@ -154,6 +187,9 @@ static void hbac_connect_done(struct tevent_req *subreq)
     if (dp_error == DP_ERR_OFFLINE) {
         /* switching to offline mode */
         talloc_zfree(hbac_ctx->sdap_op);
+
+        ipa_hbac_evaluate_rules(hbac_ctx);
+        return;
     } else if (ret != EOK) {
         goto fail;
     }
@@ -169,6 +205,24 @@ fail:
     ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
 }
 
+static void hbac_clear_rule_data(struct hbac_ctx *hbac_ctx)
+{
+    hbac_ctx->host_count = 0;
+    talloc_zfree(hbac_ctx->hosts);
+
+    hbac_ctx->hostgroup_count = 0;
+    talloc_zfree(hbac_ctx->hostgroups);
+
+    hbac_ctx->service_count = 0;
+    talloc_zfree(hbac_ctx->services);
+
+    hbac_ctx->servicegroup_count = 0;
+    talloc_zfree(hbac_ctx->servicegroups);
+
+    hbac_ctx->rule_count = 0;
+    talloc_zfree(hbac_ctx->rules);
+}
+
 /* Check the step result code and continue, retry, get offline result or abort accordingly */
 static bool hbac_check_step_result(struct hbac_ctx *hbac_ctx, int ret)
 {
@@ -189,6 +243,10 @@ static bool hbac_check_step_result(struct hbac_ctx *hbac_ctx, int ret)
         if (dp_error == DP_ERR_OFFLINE) {
             /* switching to offline mode */
             talloc_zfree(hbac_ctx->sdap_op);
+
+            /* Free any of the results we've gotten */
+            hbac_clear_rule_data(hbac_ctx);
+
             dp_error = DP_ERR_OK;
         }
 
@@ -205,173 +263,317 @@ static bool hbac_check_step_result(struct hbac_ctx *hbac_ctx, int ret)
     return false;
 }
 
+static void hbac_get_service_info_step(struct tevent_req *req);
+static void hbac_get_rule_info_step(struct tevent_req *req);
+static void hbac_sysdb_save (struct tevent_req *req);
+
 static int hbac_get_host_info_step(struct hbac_ctx *hbac_ctx)
 {
-    struct pam_data *pd = hbac_ctx->pd;
-    const char *hostlist[3];
-    struct tevent_req *subreq;
-
-    hostlist[0] = dp_opt_get_cstring(hbac_ctx->ipa_options, IPA_HOSTNAME);
-    if (hostlist[0] == NULL) {
-        DEBUG(1, ("ipa_hostname not available.\n"));
-        return EINVAL;
-    }
-    if (pd->rhost != NULL && *pd->rhost != '\0') {
-        hostlist[1] = pd->rhost;
-        hostlist[2] = NULL;
-    } else {
-        hostlist[1] = NULL;
-        pd->rhost = discard_const_p(char, hostlist[0]);
-    }
-
-    subreq = hbac_get_host_info_send(hbac_ctx, hbac_ctx, hostlist);
-    if (!subreq) {
-        DEBUG(1, ("hbac_get_host_info_send failed.\n"));
+    struct tevent_req *req =
+            ipa_hbac_host_info_send(hbac_ctx,
+                                    hbac_ctx_ev(hbac_ctx),
+                                    hbac_ctx_sysdb(hbac_ctx),
+                                    hbac_ctx_be(hbac_ctx)->domain,
+                                    sdap_id_op_handle(hbac_ctx->sdap_op),
+                                    hbac_ctx_sdap_id_ctx(hbac_ctx)->opts,
+                                    hbac_ctx->hbac_search_base);
+    if (req == NULL) {
+        DEBUG(1, ("Could not get host info\n"));
         return ENOMEM;
     }
+    tevent_req_set_callback(req, hbac_get_service_info_step, hbac_ctx);
 
-    tevent_req_set_callback(subreq, hbac_get_host_info_done, hbac_ctx);
     return EOK;
 }
 
-static void hbac_get_host_info_done(struct tevent_req *req)
+static void hbac_get_service_info_step(struct tevent_req *req)
 {
-    struct hbac_ctx *hbac_ctx = tevent_req_callback_data(req, struct hbac_ctx);
-    int ret;
-    int pam_status = PAM_SYSTEM_ERR;
+    errno_t ret;
+    struct hbac_ctx *hbac_ctx =
+            tevent_req_callback_data(req, struct hbac_ctx);
+
+    ret = ipa_hbac_host_info_recv(req, hbac_ctx,
+                                  &hbac_ctx->host_count,
+                                  &hbac_ctx->hosts,
+                                  &hbac_ctx->hostgroup_count,
+                                  &hbac_ctx->hostgroups);
+    talloc_zfree(req);
+    if (!hbac_check_step_result(hbac_ctx, ret)) {
+        return;
+    }
+
+    /* Get services and service groups */
+    req = ipa_hbac_service_info_send(hbac_ctx,
+                                    hbac_ctx_ev(hbac_ctx),
+                                    hbac_ctx_sysdb(hbac_ctx),
+                                    hbac_ctx_be(hbac_ctx)->domain,
+                                    sdap_id_op_handle(hbac_ctx->sdap_op),
+                                    hbac_ctx_sdap_id_ctx(hbac_ctx)->opts,
+                                    hbac_ctx->hbac_search_base);
+    if (req == NULL) {
+        DEBUG(1,("Could not get service info\n"));
+        goto fail;
+    }
+    tevent_req_set_callback(req, hbac_get_rule_info_step, hbac_ctx);
+    return;
+
+fail:
+    ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
+}
+
+static void hbac_get_rule_info_step(struct tevent_req *req)
+{
+    errno_t ret;
+    size_t i;
     const char *ipa_hostname;
-    struct hbac_host_info *local_hhi = NULL;
+    const char *hostname;
+    struct hbac_ctx *hbac_ctx =
+            tevent_req_callback_data(req, struct hbac_ctx);
 
-    ret = hbac_get_host_info_recv(req, hbac_ctx, &hbac_ctx->hbac_hosts_count,
-                                  &hbac_ctx->hbac_hosts_list);
+    ret = ipa_hbac_service_info_recv(req, hbac_ctx,
+                                     &hbac_ctx->service_count,
+                                     &hbac_ctx->services,
+                                     &hbac_ctx->servicegroup_count,
+                                     &hbac_ctx->servicegroups);
     talloc_zfree(req);
-
     if (!hbac_check_step_result(hbac_ctx, ret)) {
         return;
     }
 
+    /* Get the ipa_host attrs */
+    hbac_ctx->ipa_host = NULL;
     ipa_hostname = dp_opt_get_cstring(hbac_ctx->ipa_options, IPA_HOSTNAME);
     if (ipa_hostname == NULL) {
         DEBUG(1, ("Missing ipa_hostname, this should never happen.\n"));
         goto fail;
     }
 
-    ret = set_local_and_remote_host_info(hbac_ctx, hbac_ctx->hbac_hosts_count,
-                                         hbac_ctx->hbac_hosts_list, ipa_hostname,
-                                         hbac_ctx->pd->rhost, &local_hhi,
-                                         &hbac_ctx->remote_hhi);
-    if (ret != EOK) {
-        DEBUG(1, ("set_local_and_remote_host_info failed.\n"));
-        goto fail;
-     }
+    for (i = 0; i < hbac_ctx->host_count; i++) {
+        ret = sysdb_attrs_get_string(hbac_ctx->hosts[i],
+                                     IPA_HOST_FQDN,
+                                     &hostname);
+        if (ret != EOK) {
+            DEBUG(1, ("Could not locate IPA host\n"));
+            goto fail;
+        }
 
-    if (local_hhi == NULL) {
-        DEBUG(1, ("Missing host info for [%s].\n", ipa_hostname));
-        pam_status = PAM_PERM_DENIED;
+        if (strcmp(hostname, ipa_hostname) == 0) {
+            hbac_ctx->ipa_host = hbac_ctx->hosts[i];
+            break;
+        }
+    }
+    if (hbac_ctx->ipa_host == NULL) {
+        DEBUG(1, ("Could not locate IPA host\n"));
         goto fail;
     }
-    req = hbac_get_rules_send(hbac_ctx, hbac_ctx, local_hhi->dn,
-                              local_hhi->memberof);
+
+
+    /* Get the list of applicable rules */
+    req = ipa_hbac_rule_info_send(hbac_ctx,
+                                  hbac_ctx_ev(hbac_ctx),
+                                  hbac_ctx_sysdb(hbac_ctx),
+                                  hbac_ctx_be(hbac_ctx)->domain,
+                                  sdap_id_op_handle(hbac_ctx->sdap_op),
+                                  hbac_ctx_sdap_id_ctx(hbac_ctx)->opts,
+                                  hbac_ctx->hbac_search_base,
+                                  hbac_ctx->ipa_host);
     if (req == NULL) {
-        DEBUG(1, ("hbac_get_rules_send failed.\n"));
+        DEBUG(1, ("Could not get rules\n"));
         goto fail;
     }
 
-    tevent_req_set_callback(req, hbac_get_rules_done, hbac_ctx);
+    tevent_req_set_callback(req, hbac_sysdb_save, hbac_ctx);
     return;
 
 fail:
-    ipa_access_reply(hbac_ctx, pam_status);
+    ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
 }
 
-static void hbac_get_rules_done(struct tevent_req *req)
+static void hbac_sysdb_save (struct tevent_req *req)
 {
-    struct hbac_ctx *hbac_ctx = tevent_req_callback_data(req, struct hbac_ctx);
-    int ret;
-    int pam_status = PAM_SYSTEM_ERR;
-
-    hbac_ctx->hbac_rule_count = 0;
-    talloc_zfree(hbac_ctx->hbac_rule_list);
-
-    ret = hbac_get_rules_recv(req, hbac_ctx, &hbac_ctx->hbac_rule_count,
-                              &hbac_ctx->hbac_rule_list);
+    errno_t ret;
+    bool in_transaction = false;
+    struct hbac_ctx *hbac_ctx =
+            tevent_req_callback_data(req, struct hbac_ctx);
+    struct sysdb_ctx *sysdb = hbac_ctx_sysdb(hbac_ctx);
+    struct sss_domain_info *domain = hbac_ctx_be(hbac_ctx)->domain;
+
+    ret = ipa_hbac_rule_info_recv(req, hbac_ctx,
+                                  &hbac_ctx->rule_count,
+                                  &hbac_ctx->rules);
     talloc_zfree(req);
-
     if (!hbac_check_step_result(hbac_ctx, ret)) {
         return;
     }
 
-    req = hbac_get_service_data_send(hbac_ctx, hbac_ctx);
-    if (req == NULL) {
-        DEBUG(1, ("hbac_get_service_data_send failed.\n"));
-        goto failed;
+    ret = sysdb_transaction_start(sysdb);
+    if (ret != EOK) {
+        DEBUG(0, ("Could not start transaction\n"));
+        goto fail;
+    }
+    in_transaction = true;
+
+    /* Save the hosts */
+    ret = ipa_hbac_sysdb_save(sysdb, domain,
+                              HBAC_HOSTS_SUBDIR, IPA_HOST_FQDN,
+                              hbac_ctx->host_count, hbac_ctx->hosts,
+                              HBAC_HOSTGROUPS_SUBDIR, IPA_CN,
+                              hbac_ctx->hostgroup_count,
+                              hbac_ctx->hostgroups);
+    if (ret != EOK) {
+        DEBUG(1, ("Error saving hosts: [%d][%s]\n",
+                  ret, strerror(ret)));
+        goto fail;
     }
 
-    tevent_req_set_callback(req, hbac_get_service_data_done, hbac_ctx);
-    return;
+    /* Save the services */
+    ret = ipa_hbac_sysdb_save(sysdb, domain,
+                              HBAC_SERVICES_SUBDIR, IPA_CN,
+                              hbac_ctx->service_count, hbac_ctx->services,
+                              HBAC_SERVICEGROUPS_SUBDIR, IPA_CN,
+                              hbac_ctx->servicegroup_count,
+                              hbac_ctx->servicegroups);
+    if (ret != EOK) {
+        DEBUG(1, ("Error saving services:  [%d][%s]\n",
+                  ret, strerror(ret)));
+        goto fail;
+    }
+    /* Save the rules */
+    ret = ipa_hbac_sysdb_save(sysdb, domain,
+                              HBAC_RULES_SUBDIR, IPA_UNIQUE_ID,
+                              hbac_ctx->rule_count,
+                              hbac_ctx->rules,
+                              NULL, NULL, 0, NULL);
+    if (ret != EOK) {
+        DEBUG(1, ("Error saving rules:  [%d][%s]\n",
+                  ret, strerror(ret)));
+        goto fail;
+    }
 
-failed:
-    ipa_access_reply(hbac_ctx, pam_status);
-}
+    ret = sysdb_transaction_commit(sysdb);
+    if (ret != EOK) {
+        DEBUG(0, ("Failed to commit transaction\n"));
+        goto fail;
+    }
 
-static void hbac_get_service_data_done(struct tevent_req *req)
-{
-    struct hbac_ctx *hbac_ctx = tevent_req_callback_data(req, struct hbac_ctx);
-    struct pam_data *pd = hbac_ctx->pd;
-    int ret;
-    int pam_status = PAM_SYSTEM_ERR;
-    bool access_allowed = false;
-
-    hbac_ctx->hbac_services_count = 0;
-    talloc_zfree(hbac_ctx->hbac_services_list);
-
-    ret = hbac_get_service_data_recv(req, hbac_ctx,
-                                     &hbac_ctx->hbac_services_count,
-                                     &hbac_ctx->hbac_services_list);
-    talloc_zfree(req);
+    /* We don't need the rule data any longer,
+     * the rest of the processing relies on
+     * sysdb lookups.
+     */
+    hbac_clear_rule_data(hbac_ctx);
 
-    if (!hbac_check_step_result(hbac_ctx, ret)) {
-        return;
-    }
+    /* Now evaluate the request against the rules */
+    ipa_hbac_evaluate_rules(hbac_ctx);
 
-    if (hbac_ctx->user_dn) {
-        talloc_free(discard_const_p(TALLOC_CTX, hbac_ctx->user_dn));
-        hbac_ctx->user_dn = 0;
-    }
+    return;
 
-    if (!hbac_ctx_is_offline(hbac_ctx)) {
-        ret = hbac_save_data_to_sysdb(hbac_ctx);
+fail:
+    if (in_transaction) {
+        ret = sysdb_transaction_cancel(sysdb);
         if (ret != EOK) {
-            DEBUG(1, ("Failed to save data, "
-                      "offline authentication might not work.\n"));
-            /* This is not a fatal error. */
+            DEBUG(0, ("Could not cancel transaction\n"));
         }
     }
+    ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
+}
 
-    hbac_ctx->groups_count = 0;
-    talloc_zfree(hbac_ctx->groups);
+static errno_t hbac_get_cached_rules(TALLOC_CTX *mem_ctx,
+                                     struct hbac_ctx *hbac_ctx);
 
-    ret = hbac_get_user_info(hbac_ctx, hbac_ctx_be(hbac_ctx),
-                             pd->user, &hbac_ctx->user_dn,
-                             &hbac_ctx->groups_count, &hbac_ctx->groups);
+void ipa_hbac_evaluate_rules(struct hbac_ctx *hbac_ctx)
+{
+    errno_t ret;
+    struct hbac_rule **hbac_rules;
+    struct hbac_eval_req *eval_req;
+    enum hbac_eval_result result;
+    struct hbac_error *error;
+
+    /* Get HBAC rules from the sysdb */
+    ret = hbac_get_cached_rules(hbac_ctx, hbac_ctx);
     if (ret != EOK) {
-        goto failed;
+        DEBUG(1, ("Could not retrieve rules from the cache\n"));
+        ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
     }
 
-    ret = evaluate_ipa_hbac_rules(hbac_ctx, &access_allowed);
+    ret = hbac_ctx_to_rules(hbac_ctx, hbac_ctx,
+                            &hbac_rules, &eval_req);
     if (ret != EOK) {
-        DEBUG(1, ("evaluate_ipa_hbac_rules failed.\n"));
-        goto failed;
+        DEBUG(1, ("Could not construct HBAC rules\n"));
+        ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
+        return;
     }
 
-    if (access_allowed) {
-        pam_status = PAM_SUCCESS;
-        DEBUG(5, ("Access allowed.\n"));
-    } else {
-        pam_status = PAM_PERM_DENIED;
-        DEBUG(3, ("Access denied.\n"));
+    result = hbac_evaluate(hbac_rules, eval_req, &error);
+    if (result == HBAC_EVAL_ALLOW) {
+        DEBUG(3, ("Access granted by HBAC rules\n"));
+        ipa_access_reply(hbac_ctx, PAM_SUCCESS);
+        return;
+    } else if (result == HBAC_EVAL_ERROR) {
+        DEBUG(1, ("Error [%s] occurred in rule [%s]\n",
+                  hbac_error_string(error->code),
+                  error->rule_name));
+        ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR);
+        return;
+    }
+
+    DEBUG(3, ("Access denied by HBAC rules\n"));
+    ipa_access_reply(hbac_ctx, PAM_PERM_DENIED);
+}
+
+static errno_t hbac_get_cached_rules(TALLOC_CTX *mem_ctx,
+                                     struct hbac_ctx *hbac_ctx)
+{
+    errno_t ret;
+    struct sysdb_ctx *sysdb = hbac_ctx_sysdb(hbac_ctx);
+    struct sss_domain_info *domain = hbac_ctx_be(hbac_ctx)->domain;
+    size_t count;
+    struct ldb_message **msgs;
+    TALLOC_CTX *tmp_ctx;
+    char *filter;
+    const char *attrs[] = { OBJECTCLASS,
+                            IPA_CN,
+                            IPA_UNIQUE_ID,
+                            IPA_ENABLED_FLAG,
+                            IPA_ACCESS_RULE_TYPE,
+                            IPA_MEMBER_USER,
+                            IPA_USER_CATEGORY,
+                            IPA_MEMBER_SERVICE,
+                            IPA_SERVICE_CATEGORY,
+                            IPA_SOURCE_HOST,
+                            IPA_SOURCE_HOST_CATEGORY,
+                            IPA_EXTERNAL_HOST,
+                            IPA_MEMBER_HOST,
+                            IPA_HOST_CATEGORY,
+                            NULL };
+
+    tmp_ctx = talloc_new(hbac_ctx);
+    if (tmp_ctx == NULL) return ENOMEM;
+
+    filter = talloc_asprintf(tmp_ctx, "(objectClass=%s)", IPA_HBAC_RULE);
+    if (filter == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = sysdb_search_custom(mem_ctx, sysdb, domain, filter,
+                              HBAC_RULES_SUBDIR, attrs,
+                              &count, &msgs);
+    if (ret != EOK && ret != ENOENT) {
+        DEBUG(1, ("Error looking up HBAC rules"));
+        goto done;
+    } if (ret == ENOENT) {
+       count = 0;
+    }
+
+    ret = msgs2attrs_array(mem_ctx, count, msgs, &hbac_ctx->rules);
+    if (ret != EOK) {
+        DEBUG(1, ("Could not convert ldb message to sysdb_attrs\n"));
+        goto done;
     }
+    hbac_ctx->rule_count = count;
 
-failed:
-    ipa_access_reply(hbac_ctx, pam_status);
+    ret = EOK;
+done:
+    talloc_free(tmp_ctx);
+    return ret;
 }
diff --git a/src/providers/ipa/ipa_access.h b/src/providers/ipa/ipa_access.h
index d24056a839e0519e56ebd139b40e0efcc3313498..7abbe6724689ed44d1baa912f3c8d84d8057d573 100644
--- a/src/providers/ipa/ipa_access.h
+++ b/src/providers/ipa/ipa_access.h
@@ -54,6 +54,23 @@ struct hbac_ctx {
     struct pam_data *pd;
 
     char *hbac_search_base;
+
+    /* Hosts */
+    size_t host_count;
+    struct sysdb_attrs **hosts;
+    size_t hostgroup_count;
+    struct sysdb_attrs **hostgroups;
+    struct sysdb_attrs *ipa_host;
+
+    /* Rules */
+    size_t rule_count;
+    struct sysdb_attrs **rules;
+
+    /* Services */
+    size_t service_count;
+    struct sysdb_attrs **services;
+    size_t servicegroup_count;
+    struct sysdb_attrs **servicegroups;
 };
 
 /* Get BE context associated with HBAC context */
-- 
1.7.5.2

