From c772c4842f2a7861d8b5f9fc4fc9b5d97cc25eb8 Mon Sep 17 00:00:00 2001
From: Jan Zeleny <jzeleny@redhat.com>
Date: Thu, 2 Feb 2012 08:29:01 -0500
Subject: [PATCH 10/13] Separate the host-retrieval code from IPA HBAC to
 common IPA code

---
 Makefile.am                          |    2 +
 src/providers/ipa/ipa_access.c       |   56 +++--
 src/providers/ipa/ipa_access.h       |    1 +
 src/providers/ipa/ipa_hbac_hosts.c   |  434 --------------------------------
 src/providers/ipa/ipa_hbac_private.h |   19 --
 src/providers/ipa/ipa_hosts.c        |  449 ++++++++++++++++++++++++++++++++++
 src/providers/ipa/ipa_hosts.h        |   45 ++++
 7 files changed, 537 insertions(+), 469 deletions(-)
 create mode 100644 src/providers/ipa/ipa_hosts.c
 create mode 100644 src/providers/ipa/ipa_hosts.h

diff --git a/Makefile.am b/Makefile.am
index 647fbf26f9ee83e9de73795aa6694b70f325c650..9daffdba85742e5da629ad2c4d75769d0d494589 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -361,6 +361,7 @@ dist_noinst_HEADERS = \
     src/providers/ipa/ipa_common.h \
     src/providers/ipa/ipa_config.h \
     src/providers/ipa/ipa_access.h \
+    src/providers/ipa/ipa_hosts.h \
     src/providers/ipa/ipa_auth.h \
     src/providers/ipa/ipa_dyndns.h \
     src/providers/ipa/ipa_id.h \
@@ -1071,6 +1072,7 @@ libsss_ipa_la_SOURCES = \
     src/providers/ipa/ipa_auth.c \
     src/providers/ipa/ipa_access.c \
     src/providers/ipa/ipa_dyndns.c \
+    src/providers/ipa/ipa_hosts.c \
     src/providers/ipa/ipa_hbac_hosts.c \
     src/providers/ipa/ipa_hbac_private.h \
     src/providers/ipa/ipa_hbac_rules.c \
diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c
index 7d42e8b4ef32e33196d3762b47d2aeb1e2f7ffbd..03945f721f9f65d805ec598da603e293e9a065c9 100644
--- a/src/providers/ipa/ipa_access.c
+++ b/src/providers/ipa/ipa_access.c
@@ -30,6 +30,7 @@
 #include "providers/ipa/ipa_common.h"
 #include "providers/ipa/ipa_access.h"
 #include "providers/ipa/ipa_hbac.h"
+#include "providers/ipa/ipa_hosts.h"
 #include "providers/ipa/ipa_hbac_private.h"
 #include "providers/ipa/ipa_hbac_rules.h"
 
@@ -268,17 +269,40 @@ static void hbac_sysdb_save (struct tevent_req *req);
 
 static int hbac_get_host_info_step(struct hbac_ctx *hbac_ctx)
 {
-    struct tevent_req *req =
-            ipa_hbac_host_info_send(hbac_ctx,
-                                    hbac_ctx_ev(hbac_ctx),
-                                    hbac_ctx_sysdb(hbac_ctx),
-                                    sdap_id_op_handle(hbac_ctx->sdap_op),
-                                    hbac_ctx_sdap_id_ctx(hbac_ctx)->opts,
-                                    dp_opt_get_bool(hbac_ctx->ipa_options,
-                                                    IPA_HBAC_SUPPORT_SRCHOST),
-                                    dp_opt_get_string(hbac_ctx->ipa_options,
-                                                      IPA_HOSTNAME),
-                                    hbac_ctx->access_ctx->host_search_bases);
+    const char *hostname;
+    struct tevent_req *req;
+
+    hbac_ctx->host_attrs = talloc_array(hbac_ctx, const char *, 8);
+    if (hbac_ctx->host_attrs == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to allocate host attribute list.\n"));
+        return ENOMEM;
+    }
+    hbac_ctx->host_attrs[0] = "objectClass";
+    hbac_ctx->host_attrs[1] = IPA_HOST_SERVERHOSTNAME;
+    hbac_ctx->host_attrs[2] = IPA_HOST_FQDN;
+    hbac_ctx->host_attrs[3] = IPA_UNIQUE_ID;
+    hbac_ctx->host_attrs[4] = IPA_MEMBER;
+    hbac_ctx->host_attrs[5] = IPA_MEMBEROF;
+    hbac_ctx->host_attrs[6] = IPA_CN;
+    hbac_ctx->host_attrs[7] = NULL;
+
+    if (dp_opt_get_bool(hbac_ctx->ipa_options, IPA_HBAC_SUPPORT_SRCHOST)) {
+        /* Support srchost
+         * -> we don't want any particular host,
+         *    we want all hosts
+         */
+        hostname = NULL;
+    } else {
+        hostname = dp_opt_get_string(hbac_ctx->ipa_options, IPA_HOSTNAME);
+    }
+
+    req = ipa_host_info_send(hbac_ctx,
+                             hbac_ctx_ev(hbac_ctx),
+                             hbac_ctx_sysdb(hbac_ctx),
+                             sdap_id_op_handle(hbac_ctx->sdap_op),
+                             hbac_ctx_sdap_id_ctx(hbac_ctx)->opts,
+                             hostname, hbac_ctx->host_attrs, true,
+                             hbac_ctx->access_ctx->host_search_bases);
     if (req == NULL) {
         DEBUG(1, ("Could not get host info\n"));
         return ENOMEM;
@@ -294,11 +318,11 @@ static void hbac_get_service_info_step(struct tevent_req *req)
     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);
+    ret = ipa_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;
diff --git a/src/providers/ipa/ipa_access.h b/src/providers/ipa/ipa_access.h
index 655710132fe5e5db5094b8720eb90bedc91535a4..2c7a6e815cc463d99a0b27647d8675e334bb62f3 100644
--- a/src/providers/ipa/ipa_access.h
+++ b/src/providers/ipa/ipa_access.h
@@ -61,6 +61,7 @@ struct hbac_ctx {
     struct sdap_search_base **search_bases;
 
     /* Hosts */
+    const char **host_attrs;
     size_t host_count;
     struct sysdb_attrs **hosts;
     size_t hostgroup_count;
diff --git a/src/providers/ipa/ipa_hbac_hosts.c b/src/providers/ipa/ipa_hbac_hosts.c
index 329fdc8845db14b0040b8aa5074256ee404709b2..1626f178a319e43ceb323a2d67deac13bf4be2f6 100644
--- a/src/providers/ipa/ipa_hbac_hosts.c
+++ b/src/providers/ipa/ipa_hbac_hosts.c
@@ -25,440 +25,6 @@
 #include "providers/ipa/ipa_hbac_private.h"
 #include "providers/ldap/sdap_async.h"
 
-struct ipa_hbac_host_state {
-    struct tevent_context *ev;
-    struct sysdb_ctx *sysdb;
-    struct sdap_handle *sh;
-    struct sdap_options *opts;
-    const char **attrs;
-
-    struct sdap_search_base **search_bases;
-    int search_base_iter;
-
-    char *cur_filter;
-    char *host_filter;
-
-    bool support_srchost;
-    const char *hostname;
-
-    /* Return values */
-    size_t host_count;
-    struct sysdb_attrs **hosts;
-
-    size_t hostgroup_count;
-    struct sysdb_attrs **hostgroups;
-    struct sdap_attr_map_info *hostgroup_map;
-};
-
-#define HOSTGROUP_MAP_ATTRS_COUNT 5
-static struct sdap_attr_map hostgroup_map[] = {
-    {"objectclass", "ipahostgroup", "hostgroup", NULL},
-    {"name_attr", IPA_CN, IPA_CN, NULL},
-    {"member", IPA_MEMBER, SYSDB_ORIG_MEMBER, NULL},
-    {"memberof", IPA_MEMBEROF, SYSDB_ORIG_MEMBEROF, NULL},
-    {"ipa_id", IPA_UNIQUE_ID, IPA_UNIQUE_ID, NULL}
-};
-
-static void
-ipa_hbac_host_info_done(struct tevent_req *subreq);
-
-static void
-ipa_hbac_hostgroup_info_done(struct tevent_req *subreq);
-
-static errno_t
-ipa_hbac_host_info_next(struct tevent_req *req,
-                        struct ipa_hbac_host_state *state);
-static errno_t
-ipa_hbac_hostgroup_info_next(struct tevent_req *req,
-                             struct ipa_hbac_host_state *state);
-
-struct tevent_req *
-ipa_hbac_host_info_send(TALLOC_CTX *mem_ctx,
-                        struct tevent_context *ev,
-                        struct sysdb_ctx *sysdb,
-                        struct sdap_handle *sh,
-                        struct sdap_options *opts,
-                        bool support_srchost,
-                        const char *hostname,
-                        struct sdap_search_base **search_bases)
-{
-    errno_t ret;
-    struct ipa_hbac_host_state *state;
-    struct tevent_req *req;
-
-    req = tevent_req_create(mem_ctx, &state, struct ipa_hbac_host_state);
-    if (req == NULL) {
-        return NULL;
-    }
-
-    state->ev = ev;
-    state->sysdb = sysdb;
-    state->sh = sh;
-    state->opts = opts;
-    state->support_srchost = support_srchost;
-    state->hostname = hostname;
-    state->search_bases = search_bases;
-    state->search_base_iter = 0;
-    state->cur_filter = NULL;
-
-    if (support_srchost) {
-        state->host_filter = talloc_asprintf(state, "(objectClass=%s)",
-                                             IPA_HOST);
-    } else {
-        if (hostname == NULL) {
-            ret = EINVAL;
-            goto immediate;
-        }
-        state->host_filter = talloc_asprintf(state, "(&(objectClass=%s)(%s=%s))",
-                                             IPA_HOST, IPA_HOST_FQDN, hostname);
-    }
-    if (state->host_filter == NULL) {
-        ret = ENOMEM;
-        goto immediate;
-    }
-
-    state->attrs = talloc_array(state, const char *, 8);
-    if (state->attrs == NULL) {
-        DEBUG(1, ("Failed to allocate host attribute list.\n"));
-        ret = ENOMEM;
-        goto immediate;
-    }
-    state->attrs[0] = "objectClass";
-    state->attrs[1] = IPA_HOST_SERVERHOSTNAME;
-    state->attrs[2] = IPA_HOST_FQDN;
-    state->attrs[3] = IPA_UNIQUE_ID;
-    state->attrs[4] = IPA_MEMBER;
-    state->attrs[5] = IPA_MEMBEROF;
-    state->attrs[6] = IPA_CN;
-    state->attrs[7] = NULL;
-
-    ret = ipa_hbac_host_info_next(req, state);
-    if (ret == EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE, ("No host search base configured?\n"));
-        ret = EINVAL;
-    }
-
-    if (ret != EAGAIN) {
-        goto immediate;
-    }
-
-    return req;
-
-immediate:
-    if (ret == EOK) {
-        tevent_req_done(req);
-    } else {
-        tevent_req_error(req, ret);
-    }
-    tevent_req_post(req, ev);
-    return req;
-}
-
-static errno_t ipa_hbac_host_info_next(struct tevent_req *req,
-                                       struct ipa_hbac_host_state *state)
-{
-    struct sdap_search_base *base;
-    struct tevent_req *subreq;
-
-    base = state->search_bases[state->search_base_iter];
-    if (base == NULL) {
-        return EOK;
-    }
-
-    talloc_zfree(state->cur_filter);
-    state->cur_filter = sdap_get_id_specific_filter(state, state->host_filter,
-                                                    base->filter);
-    if (state->cur_filter == NULL) {
-        return ENOMEM;
-    }
-
-    subreq = sdap_get_generic_send(state, state->ev, state->opts,
-                                   state->sh, base->basedn,
-                                   base->scope, state->cur_filter,
-                                   state->attrs, NULL, 0,
-                                   dp_opt_get_int(state->opts->basic,
-                                                  SDAP_ENUM_SEARCH_TIMEOUT));
-    if (subreq == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, ("Error requesting host info\n"));
-        talloc_zfree(state->cur_filter);
-        return EIO;
-    }
-    tevent_req_set_callback(subreq, ipa_hbac_host_info_done, req);
-
-    return EAGAIN;
-}
-
-static void
-ipa_hbac_host_info_done(struct tevent_req *subreq)
-{
-    errno_t ret;
-    struct tevent_req *req =
-            tevent_req_callback_data(subreq, struct tevent_req);
-    struct ipa_hbac_host_state *state =
-            tevent_req_data(req, struct ipa_hbac_host_state);
-    const char *host_dn;
-    int i;
-
-    ret = sdap_get_generic_recv(subreq, state,
-                                &state->host_count,
-                                &state->hosts);
-    talloc_zfree(subreq);
-    if (ret != EOK) {
-        tevent_req_error(req, ret);
-        return;
-    }
-
-    if (state->host_count == 0) {
-        state->search_base_iter++;
-        ret = ipa_hbac_host_info_next(req, state);
-        if (ret == EOK) {
-            /* No more search bases to try */
-            tevent_req_error(req, ENOENT);
-        } else if (ret != EAGAIN) {
-            tevent_req_error(req, ret);
-        }
-        return;
-    }
-
-    ret = replace_attribute_name(IPA_MEMBEROF, SYSDB_ORIG_MEMBEROF,
-                                 state->host_count,
-                                 state->hosts);
-    if (ret != EOK) {
-        DEBUG(1, ("Could not replace attribute names\n"));
-        tevent_req_error(req, ret);
-        return;
-    }
-
-    /* Complete the map */
-    for (i = 0; i < HOSTGROUP_MAP_ATTRS_COUNT; i++) {
-        /* These are allocated on the state, so the next time they'll
-         * have to be allocated again
-         */
-        hostgroup_map[i].name = talloc_strdup(state,
-                                              hostgroup_map[i].def_name);
-        if (hostgroup_map[i].name == NULL) {
-            tevent_req_error(req, ret);
-            return;
-        }
-    }
-
-    /* Look up host groups */
-    if (state->support_srchost) {
-        talloc_zfree(state->host_filter);
-        state->host_filter = talloc_asprintf(state, "(objectClass=%s)",
-                                             IPA_HOSTGROUP);
-        if (state->host_filter == NULL) {
-            tevent_req_error(req, ENOMEM);
-            return;
-        }
-        state->search_base_iter = 0;
-
-        ret = ipa_hbac_hostgroup_info_next(req, state);
-        if (ret == EOK) {
-            DEBUG(SSSDBG_CRIT_FAILURE, ("No host search base configured?\n"));
-            tevent_req_error(req, EINVAL);
-            return;
-        } else if (ret != EAGAIN) {
-            tevent_req_error(req, ret);
-            return;
-        }
-    } else {
-        state->hostgroup_map = talloc_zero(state, struct sdap_attr_map_info);
-        if (state->hostgroup_map == NULL) {
-            tevent_req_error(req, ENOMEM);
-            return;
-        }
-        state->hostgroup_map->map = hostgroup_map;
-        state->hostgroup_map->num_attrs = HOSTGROUP_MAP_ATTRS_COUNT;
-
-        ret = sysdb_attrs_get_string(state->hosts[0], SYSDB_ORIG_DN, &host_dn);
-        if (ret != EOK) {
-            tevent_req_error(req, ret);
-            return;
-        }
-
-        subreq = sdap_deref_search_send(state, state->ev, state->opts, state->sh,
-                                        host_dn, IPA_MEMBEROF, state->attrs,
-                                        1, state->hostgroup_map,
-                                        dp_opt_get_int(state->opts->basic,
-                                                       SDAP_ENUM_SEARCH_TIMEOUT));
-        if (subreq == NULL) {
-            DEBUG(SSSDBG_CRIT_FAILURE, ("Error requesting host info\n"));
-            tevent_req_error(req, EIO);
-            return;
-        }
-    }
-    tevent_req_set_callback(subreq, ipa_hbac_hostgroup_info_done, req);
-}
-
-static errno_t ipa_hbac_hostgroup_info_next(struct tevent_req *req,
-                                            struct ipa_hbac_host_state *state)
-{
-    struct sdap_search_base *base;
-    struct tevent_req *subreq;
-
-    base = state->search_bases[state->search_base_iter];
-    if (base == NULL) {
-        return EOK;
-    }
-
-    talloc_zfree(state->cur_filter);
-    state->cur_filter = sdap_get_id_specific_filter(state, state->host_filter,
-                                                    base->filter);
-    if (state->cur_filter == NULL) {
-        return ENOMEM;
-    }
-
-    subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
-                                   base->basedn, base->scope,
-                                   state->cur_filter, state->attrs, hostgroup_map,
-                                   HOSTGROUP_MAP_ATTRS_COUNT,
-                                   dp_opt_get_int(state->opts->basic,
-                                                  SDAP_ENUM_SEARCH_TIMEOUT));
-    if (subreq == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, ("Error requesting hostgroup info\n"));
-        talloc_zfree(state->cur_filter);
-        return EIO;
-    }
-    tevent_req_set_callback(subreq, ipa_hbac_hostgroup_info_done, req);
-
-    return EAGAIN;
-}
-
-static void
-ipa_hbac_hostgroup_info_done(struct tevent_req *subreq)
-{
-    errno_t ret;
-    struct tevent_req *req =
-            tevent_req_callback_data(subreq, struct tevent_req);
-    struct ipa_hbac_host_state *state =
-            tevent_req_data(req, struct ipa_hbac_host_state);
-
-    size_t hostgroups_total;
-    size_t hostgroup_count;
-    struct sysdb_attrs **hostgroups;
-    struct sdap_deref_attrs **deref_result;
-    const char *hostgroup_name;
-    const char *hostgroup_dn;
-    int i, j;
-
-    if (state->support_srchost) {
-        ret = sdap_get_generic_recv(subreq, state,
-                                    &hostgroup_count,
-                                    &hostgroups);
-        talloc_zfree(subreq);
-
-        /* Merge the two arrays */
-        if (hostgroup_count > 0) {
-            hostgroups_total = hostgroup_count + state->hostgroup_count;
-            state->hostgroups = talloc_realloc(state, state->hostgroups,
-                                               struct sysdb_attrs *,
-                                               hostgroups_total);
-            if (state->hostgroups == NULL) {
-                tevent_req_error(req, ENOMEM);
-                return;
-            }
-
-            i = 0;
-            while(state->hostgroup_count < hostgroups_total) {
-                state->hostgroups[state->hostgroup_count] =
-                    talloc_steal(state->hostgroups, hostgroups[i]);
-                state->hostgroup_count++;
-                i++;
-            }
-        }
-
-        /* Now look in the next base */
-        state->search_base_iter++;
-        ret = ipa_hbac_hostgroup_info_next(req, state);
-        if (ret != EOK && ret != EAGAIN) {
-            tevent_req_error(req, ret);
-        }
-
-        if (ret != EOK) {
-            /* Only continue if no error occurred
-             * and no req was created */
-            return;
-        }
-    } else {
-        ret = sdap_deref_search_recv(subreq, state,
-                                     &state->hostgroup_count,
-                                     &deref_result);
-        talloc_zfree(subreq);
-        if (ret != EOK) goto done;
-
-        if (state->hostgroup_count == 0) {
-            DEBUG(SSSDBG_FUNC_DATA, ("No host groups were dereferenced\n"));
-        } else {
-            state->hostgroups = talloc_zero_array(state, struct sysdb_attrs *,
-                                                  state->hostgroup_count);
-            if (state->hostgroups == NULL) {
-                ret = ENOMEM;
-                goto done;
-            }
-
-            j = 0;
-            for (i = 0; i < state->hostgroup_count; i++) {
-                ret = sysdb_attrs_get_string(deref_result[i]->attrs,
-                                             SYSDB_ORIG_DN, &hostgroup_dn);
-                if (ret != EOK) goto done;
-
-                if (!sss_ldap_dn_in_search_bases(state, hostgroup_dn,
-                                                 state->search_bases,
-                                                 NULL)) {
-                    continue;
-                }
-
-                ret = sysdb_attrs_get_string(deref_result[i]->attrs,
-                                             IPA_CN, &hostgroup_name);
-                if (ret != EOK) goto done;
-
-                DEBUG(SSSDBG_FUNC_DATA, ("Dereferenced host group: %s\n",
-                                        hostgroup_name));
-                state->hostgroups[j] = talloc_steal(state->hostgroups,
-                                                    deref_result[i]->attrs);
-                j++;
-            }
-            state->hostgroup_count = j;
-        }
-    }
-
-done:
-    if (ret == EOK) {
-        tevent_req_done(req);
-    } else {
-        DEBUG(3, ("Error [%d][%s]\n", ret, strerror(ret)));
-        tevent_req_error(req, ret);
-    }
-}
-
-errno_t
-ipa_hbac_host_info_recv(struct tevent_req *req,
-                        TALLOC_CTX *mem_ctx,
-                        size_t *host_count,
-                        struct sysdb_attrs ***hosts,
-                        size_t *hostgroup_count,
-                        struct sysdb_attrs ***hostgroups)
-{
-    size_t c;
-    struct ipa_hbac_host_state *state =
-            tevent_req_data(req, struct ipa_hbac_host_state);
-
-    TEVENT_REQ_RETURN_ON_ERROR(req);
-
-    *host_count = state->host_count;
-    *hosts = talloc_steal(mem_ctx, state->hosts);
-    for (c = 0; c < state->host_count; c++) {
-        /* Guarantee the memory heirarchy of the list */
-        talloc_steal(state->hosts, state->hosts[c]);
-    }
-
-    *hostgroup_count = state->hostgroup_count;
-    *hostgroups = talloc_steal(mem_ctx, state->hostgroups);
-
-    return EOK;
-}
-
 /*
  * Functions to convert sysdb_attrs to the hbac_rule format
  */
diff --git a/src/providers/ipa/ipa_hbac_private.h b/src/providers/ipa/ipa_hbac_private.h
index 8d735b8bd06d5f98ea71b25945f9f37ab7dfcac4..acf5671578dd6611b600bcb549cc0e3e1e86251e 100644
--- a/src/providers/ipa/ipa_hbac_private.h
+++ b/src/providers/ipa/ipa_hbac_private.h
@@ -98,25 +98,6 @@ hbac_get_category(struct sysdb_attrs *attrs,
                   const char *category_attr,
                   uint32_t *_categories);
 
-/* From ipa_hbac_hosts.c */
-struct tevent_req *
-ipa_hbac_host_info_send(TALLOC_CTX *mem_ctx,
-                        struct tevent_context *ev,
-                        struct sysdb_ctx *sysdb,
-                        struct sdap_handle *sh,
-                        struct sdap_options *opts,
-                        bool support_srchost,
-                        const char *hostname,
-                        struct sdap_search_base **search_bases);
-
-errno_t
-ipa_hbac_host_info_recv(struct tevent_req *req,
-                        TALLOC_CTX *mem_ctx,
-                        size_t *host_count,
-                        struct sysdb_attrs ***hosts,
-                        size_t *hostgroup_count,
-                        struct sysdb_attrs ***hostgroups);
-
 errno_t
 hbac_thost_attrs_to_rule(TALLOC_CTX *mem_ctx,
                          struct sysdb_ctx *sysdb,
diff --git a/src/providers/ipa/ipa_hosts.c b/src/providers/ipa/ipa_hosts.c
new file mode 100644
index 0000000000000000000000000000000000000000..04ce9adfdb23204b9dc7428de96b277c39ade5b5
--- /dev/null
+++ b/src/providers/ipa/ipa_hosts.c
@@ -0,0 +1,449 @@
+/*
+    SSSD
+
+    Authors:
+        Jan Zeleny <jzeleny@redhat.com>
+
+    Copyright (C) 2012 Red Hat
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "util/util.h"
+#include "db/sysdb.h"
+#include "providers/ldap/sdap_async.h"
+#include "providers/ipa/ipa_hosts.h"
+/* FIXME: this is temporary, use proper map instead */
+#include "providers/ipa/ipa_hbac_private.h"
+
+struct ipa_host_state {
+    struct tevent_context *ev;
+    struct sysdb_ctx *sysdb;
+    struct sdap_handle *sh;
+    struct sdap_options *opts;
+    const char **attrs;
+
+    struct sdap_search_base **search_bases;
+    int search_base_iter;
+
+    char *cur_filter;
+    char *host_filter;
+
+    const char *hostname;
+
+    /* Return values */
+    size_t host_count;
+    struct sysdb_attrs **hosts;
+
+    bool fetch_hostgroups;
+    size_t hostgroup_count;
+    struct sysdb_attrs **hostgroups;
+    struct sdap_attr_map_info *hostgroup_map;
+};
+
+#define HOSTGROUP_MAP_ATTRS_COUNT 5
+static struct sdap_attr_map hostgroup_map[] = {
+    {"objectclass", "ipahostgroup", "hostgroup", NULL},
+    {"name_attr", IPA_CN, IPA_CN, NULL},
+    {"member", IPA_MEMBER, SYSDB_ORIG_MEMBER, NULL},
+    {"memberof", IPA_MEMBEROF, SYSDB_ORIG_MEMBEROF, NULL},
+    {"ipa_id", IPA_UNIQUE_ID, IPA_UNIQUE_ID, NULL}
+};
+
+static void
+ipa_host_info_done(struct tevent_req *subreq);
+
+static void
+ipa_hostgroup_info_done(struct tevent_req *subreq);
+
+static errno_t
+ipa_host_info_next(struct tevent_req *req,
+                        struct ipa_host_state *state);
+static errno_t
+ipa_hostgroup_info_next(struct tevent_req *req,
+                             struct ipa_host_state *state);
+
+struct tevent_req *
+ipa_host_info_send(TALLOC_CTX *mem_ctx,
+                   struct tevent_context *ev,
+                   struct sysdb_ctx *sysdb,
+                   struct sdap_handle *sh,
+                   struct sdap_options *opts,
+                   const char *hostname,
+                   const char **attrs,
+                   bool fetch_hostgroups,
+                   struct sdap_search_base **search_bases)
+{
+    errno_t ret;
+    struct ipa_host_state *state;
+    struct tevent_req *req;
+
+    req = tevent_req_create(mem_ctx, &state, struct ipa_host_state);
+    if (req == NULL) {
+        return NULL;
+    }
+
+    state->ev = ev;
+    state->sysdb = sysdb;
+    state->sh = sh;
+    state->opts = opts;
+    state->hostname = hostname;
+    state->search_bases = search_bases;
+    state->search_base_iter = 0;
+    state->cur_filter = NULL;
+    state->attrs = attrs;
+    state->fetch_hostgroups = fetch_hostgroups;
+
+    if (hostname == NULL) {
+        state->host_filter = talloc_asprintf(state, "(objectClass=%s)",
+                                             IPA_HOST);
+    } else {
+        state->host_filter = talloc_asprintf(state, "(&(objectClass=%s)(%s=%s))",
+                                             IPA_HOST, IPA_HOST_FQDN, hostname);
+    }
+    if (state->host_filter == NULL) {
+        ret = ENOMEM;
+        goto immediate;
+    }
+
+    ret = ipa_host_info_next(req, state);
+    if (ret == EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("No host search base configured?\n"));
+        ret = EINVAL;
+    }
+
+    if (ret != EAGAIN) {
+        goto immediate;
+    }
+
+    return req;
+
+immediate:
+    if (ret == EOK) {
+        tevent_req_done(req);
+    } else {
+        tevent_req_error(req, ret);
+    }
+    tevent_req_post(req, ev);
+    return req;
+}
+
+static errno_t ipa_host_info_next(struct tevent_req *req,
+                                       struct ipa_host_state *state)
+{
+    struct sdap_search_base *base;
+    struct tevent_req *subreq;
+
+    base = state->search_bases[state->search_base_iter];
+    if (base == NULL) {
+        return EOK;
+    }
+
+    talloc_zfree(state->cur_filter);
+    state->cur_filter = sdap_get_id_specific_filter(state, state->host_filter,
+                                                    base->filter);
+    if (state->cur_filter == NULL) {
+        return ENOMEM;
+    }
+
+    subreq = sdap_get_generic_send(state, state->ev, state->opts,
+                                   state->sh, base->basedn,
+                                   base->scope, state->cur_filter,
+                                   state->attrs, NULL, 0,
+                                   dp_opt_get_int(state->opts->basic,
+                                                  SDAP_ENUM_SEARCH_TIMEOUT));
+    if (subreq == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Error requesting host info\n"));
+        talloc_zfree(state->cur_filter);
+        return EIO;
+    }
+    tevent_req_set_callback(subreq, ipa_host_info_done, req);
+
+    return EAGAIN;
+}
+
+static void
+ipa_host_info_done(struct tevent_req *subreq)
+{
+    errno_t ret;
+    struct tevent_req *req =
+            tevent_req_callback_data(subreq, struct tevent_req);
+    struct ipa_host_state *state =
+            tevent_req_data(req, struct ipa_host_state);
+    const char *host_dn;
+    int i;
+
+    ret = sdap_get_generic_recv(subreq, state,
+                                &state->host_count,
+                                &state->hosts);
+    talloc_zfree(subreq);
+    if (ret != EOK) {
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    if (state->host_count == 0) {
+        state->search_base_iter++;
+        ret = ipa_host_info_next(req, state);
+        if (ret == EOK) {
+            /* No more search bases to try */
+            tevent_req_error(req, ENOENT);
+        } else if (ret != EAGAIN) {
+            tevent_req_error(req, ret);
+        }
+        return;
+    }
+
+    ret = replace_attribute_name(IPA_MEMBEROF, SYSDB_ORIG_MEMBEROF,
+                                 state->host_count,
+                                 state->hosts);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Could not replace attribute names\n"));
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    /* Complete the map */
+    for (i = 0; i < HOSTGROUP_MAP_ATTRS_COUNT; i++) {
+        /* These are allocated on the state, so the next time they'll
+         * have to be allocated again
+         */
+        hostgroup_map[i].name = talloc_strdup(state,
+                                              hostgroup_map[i].def_name);
+        if (hostgroup_map[i].name == NULL) {
+            tevent_req_error(req, ret);
+            return;
+        }
+    }
+
+    if (state->fetch_hostgroups) {
+        /* Look up host groups */
+        if (state->hostname == NULL) {
+            talloc_zfree(state->host_filter);
+            state->host_filter = talloc_asprintf(state, "(objectClass=%s)",
+                                                 IPA_HOSTGROUP);
+            if (state->host_filter == NULL) {
+                tevent_req_error(req, ENOMEM);
+                return;
+            }
+            state->search_base_iter = 0;
+
+            ret = ipa_hostgroup_info_next(req, state);
+            if (ret == EOK) {
+                DEBUG(SSSDBG_CRIT_FAILURE, ("No host search base configured?\n"));
+                tevent_req_error(req, EINVAL);
+                return;
+            } else if (ret != EAGAIN) {
+                tevent_req_error(req, ret);
+                return;
+            }
+        } else {
+            state->hostgroup_map = talloc_zero(state, struct sdap_attr_map_info);
+            if (state->hostgroup_map == NULL) {
+                tevent_req_error(req, ENOMEM);
+                return;
+            }
+            state->hostgroup_map->map = hostgroup_map;
+            state->hostgroup_map->num_attrs = HOSTGROUP_MAP_ATTRS_COUNT;
+
+            ret = sysdb_attrs_get_string(state->hosts[0], SYSDB_ORIG_DN, &host_dn);
+            if (ret != EOK) {
+                tevent_req_error(req, ret);
+                return;
+            }
+
+            subreq = sdap_deref_search_send(state, state->ev, state->opts, state->sh,
+                                            host_dn, IPA_MEMBEROF, state->attrs,
+                                            1, state->hostgroup_map,
+                                            dp_opt_get_int(state->opts->basic,
+                                                           SDAP_ENUM_SEARCH_TIMEOUT));
+            if (subreq == NULL) {
+                DEBUG(SSSDBG_CRIT_FAILURE, ("Error requesting host info\n"));
+                tevent_req_error(req, EIO);
+                return;
+            }
+        }
+        tevent_req_set_callback(subreq, ipa_hostgroup_info_done, req);
+    } else {
+        /* Nothing else to do, just complete the req */
+        tevent_req_done(req);
+    }
+}
+
+static errno_t ipa_hostgroup_info_next(struct tevent_req *req,
+                                            struct ipa_host_state *state)
+{
+    struct sdap_search_base *base;
+    struct tevent_req *subreq;
+
+    base = state->search_bases[state->search_base_iter];
+    if (base == NULL) {
+        return EOK;
+    }
+
+    talloc_zfree(state->cur_filter);
+    state->cur_filter = sdap_get_id_specific_filter(state, state->host_filter,
+                                                    base->filter);
+    if (state->cur_filter == NULL) {
+        return ENOMEM;
+    }
+
+    subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
+                                   base->basedn, base->scope,
+                                   state->cur_filter, state->attrs, hostgroup_map,
+                                   HOSTGROUP_MAP_ATTRS_COUNT,
+                                   dp_opt_get_int(state->opts->basic,
+                                                  SDAP_ENUM_SEARCH_TIMEOUT));
+    if (subreq == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Error requesting hostgroup info\n"));
+        talloc_zfree(state->cur_filter);
+        return EIO;
+    }
+    tevent_req_set_callback(subreq, ipa_hostgroup_info_done, req);
+
+    return EAGAIN;
+}
+
+static void
+ipa_hostgroup_info_done(struct tevent_req *subreq)
+{
+    errno_t ret;
+    struct tevent_req *req =
+            tevent_req_callback_data(subreq, struct tevent_req);
+    struct ipa_host_state *state =
+            tevent_req_data(req, struct ipa_host_state);
+
+    size_t hostgroups_total;
+    size_t hostgroup_count;
+    struct sysdb_attrs **hostgroups;
+    struct sdap_deref_attrs **deref_result;
+    const char *hostgroup_name;
+    const char *hostgroup_dn;
+    int i, j;
+
+    if (state->hostname == NULL) {
+        ret = sdap_get_generic_recv(subreq, state,
+                                    &hostgroup_count,
+                                    &hostgroups);
+        talloc_zfree(subreq);
+
+        /* Merge the two arrays */
+        if (hostgroup_count > 0) {
+            hostgroups_total = hostgroup_count + state->hostgroup_count;
+            state->hostgroups = talloc_realloc(state, state->hostgroups,
+                                               struct sysdb_attrs *,
+                                               hostgroups_total);
+            if (state->hostgroups == NULL) {
+                tevent_req_error(req, ENOMEM);
+                return;
+            }
+
+            i = 0;
+            while(state->hostgroup_count < hostgroups_total) {
+                state->hostgroups[state->hostgroup_count] =
+                    talloc_steal(state->hostgroups, hostgroups[i]);
+                state->hostgroup_count++;
+                i++;
+            }
+        }
+
+        /* Now look in the next base */
+        state->search_base_iter++;
+        ret = ipa_hostgroup_info_next(req, state);
+        if (ret != EOK && ret != EAGAIN) {
+            tevent_req_error(req, ret);
+        }
+
+        if (ret != EOK) {
+            /* Only continue if no error occurred
+             * and no req was created */
+            return;
+        }
+    } else {
+        ret = sdap_deref_search_recv(subreq, state,
+                                     &state->hostgroup_count,
+                                     &deref_result);
+        talloc_zfree(subreq);
+        if (ret != EOK) goto done;
+
+        if (state->hostgroup_count == 0) {
+            DEBUG(SSSDBG_FUNC_DATA, ("No host groups were dereferenced\n"));
+        } else {
+            state->hostgroups = talloc_zero_array(state, struct sysdb_attrs *,
+                                                  state->hostgroup_count);
+            if (state->hostgroups == NULL) {
+                ret = ENOMEM;
+                goto done;
+            }
+
+            j = 0;
+            for (i = 0; i < state->hostgroup_count; i++) {
+                ret = sysdb_attrs_get_string(deref_result[i]->attrs,
+                                             SYSDB_ORIG_DN, &hostgroup_dn);
+                if (ret != EOK) goto done;
+
+                if (!sss_ldap_dn_in_search_bases(state, hostgroup_dn,
+                                                 state->search_bases,
+                                                 NULL)) {
+                    continue;
+                }
+
+                ret = sysdb_attrs_get_string(deref_result[i]->attrs,
+                                             IPA_CN, &hostgroup_name);
+                if (ret != EOK) goto done;
+
+                DEBUG(SSSDBG_FUNC_DATA, ("Dereferenced host group: %s\n",
+                                        hostgroup_name));
+                state->hostgroups[j] = talloc_steal(state->hostgroups,
+                                                    deref_result[i]->attrs);
+                j++;
+            }
+            state->hostgroup_count = j;
+        }
+    }
+
+done:
+    if (ret == EOK) {
+        tevent_req_done(req);
+    } else {
+        DEBUG(SSSDBG_OP_FAILURE, ("Error [%d][%s]\n", ret, strerror(ret)));
+        tevent_req_error(req, ret);
+    }
+}
+
+errno_t ipa_host_info_recv(struct tevent_req *req,
+                           TALLOC_CTX *mem_ctx,
+                           size_t *host_count,
+                           struct sysdb_attrs ***hosts,
+                           size_t *hostgroup_count,
+                           struct sysdb_attrs ***hostgroups)
+{
+    size_t c;
+    struct ipa_host_state *state =
+            tevent_req_data(req, struct ipa_host_state);
+
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    *host_count = state->host_count;
+    *hosts = talloc_steal(mem_ctx, state->hosts);
+    for (c = 0; c < state->host_count; c++) {
+        /* Guarantee the memory heirarchy of the list */
+        talloc_steal(state->hosts, state->hosts[c]);
+    }
+
+    *hostgroup_count = state->hostgroup_count;
+    *hostgroups = talloc_steal(mem_ctx, state->hostgroups);
+
+    return EOK;
+}
diff --git a/src/providers/ipa/ipa_hosts.h b/src/providers/ipa/ipa_hosts.h
new file mode 100644
index 0000000000000000000000000000000000000000..cc658f0df867f91a3cdf744c1076e9c12eb0f313
--- /dev/null
+++ b/src/providers/ipa/ipa_hosts.h
@@ -0,0 +1,45 @@
+/*
+    SSSD
+
+    Authors:
+        Jan Zeleny <jzeleny@redhat.com>
+
+    Copyright (C) 2012 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/>.
+*/
+
+#ifndef IPA_HOSTS_H_
+#define IPA_HOSTS_H_
+
+struct tevent_req *
+ipa_host_info_send(TALLOC_CTX *mem_ctx,
+                   struct tevent_context *ev,
+                   struct sysdb_ctx *sysdb,
+                   struct sdap_handle *sh,
+                   struct sdap_options *opts,
+                   const char *hostname,
+                   const char **attrs,
+                   bool fetch_hostgroups,
+                   struct sdap_search_base **search_bases);
+
+errno_t
+ipa_host_info_recv(struct tevent_req *req,
+                   TALLOC_CTX *mem_ctx,
+                   size_t *host_count,
+                   struct sysdb_attrs ***hosts,
+                   size_t *hostgroup_count,
+                   struct sysdb_attrs ***hostgroups);
+
+#endif /* IPA_HOSTS_H_ */
-- 
1.7.6.4

