URL: https://github.com/SSSD/sssd/pull/237
Author: hvenev
 Title: #237: providers: Move hostid from ipa to sdap
Action: synchronized

To pull the PR as Git branch:
git remote add ghsssd https://github.com/SSSD/sssd
git fetch ghsssd pull/237/head:pr237
git checkout pr237
From 40c0186fac68bdd466d23d1672ea7eb7f6b0d4a9 Mon Sep 17 00:00:00 2001
From: Hristo Venev <hri...@venev.name>
Date: Wed, 3 May 2017 16:31:39 +0100
Subject: [PATCH] providers: Move hostid from ipa to sdap, v2

In the ldap provider, all option names are renamed to ldap_host_*. In
the ipa provider the names are still ipa_host_*.

Hostgroups are disabled in the ldap provider. sss_ssh_knownhostsproxy
works.

For now, there is no struct sdap_hostid_ctx as all information is
contained in struct sdap_id_ctx. There is no struct ipa_hostid_ctx
either.

I've also added some documentation for the ldap provider.
---
 Makefile.am                                        |   7 +-
 src/man/sssd-ipa.5.xml                             |  20 +-
 src/man/sssd-ldap.5.xml                            | 109 +++++++
 src/providers/ad/ad_opts.c                         |   1 +
 src/providers/ipa/ipa_common.c                     |  33 ++-
 src/providers/ipa/ipa_common.h                     |  21 +-
 src/providers/ipa/ipa_hostid.c                     | 301 +------------------
 src/providers/ipa/ipa_hosts.c                      | 151 ++--------
 src/providers/ipa/ipa_hosts.h                      |   3 +-
 src/providers/ipa/ipa_init.c                       |  24 +-
 src/providers/ipa/ipa_netgroups.c                  |  14 +-
 src/providers/ipa/ipa_opts.c                       |   1 +
 src/providers/ipa/ipa_selinux.c                    |   2 +-
 src/providers/ipa/ipa_subdomains.c                 |   6 +-
 src/providers/ipa/ipa_sudo_async.c                 |   6 +-
 src/providers/ipa/ipa_sudo_conversion.c            |   2 +-
 src/providers/ldap/ldap_init.c                     |  21 ++
 src/providers/ldap/ldap_options.c                  |  23 ++
 src/providers/ldap/ldap_opts.c                     |  12 +
 src/providers/ldap/ldap_opts.h                     |   2 +
 src/providers/ldap/sdap.c                          |  12 +
 src/providers/ldap/sdap.h                          |  15 +
 src/providers/ldap/sdap_async.h                    |  15 +
 src/providers/ldap/sdap_async_hosts.c              | 212 ++++++++++++++
 src/providers/ldap/sdap_hostid.c                   | 324 +++++++++++++++++++++
 .../{ipa/ipa_hostid.h => ldap/sdap_hostid.h}       |  31 +-
 src/tests/ipa_ldap_opt-tests.c                     |   2 +-
 27 files changed, 856 insertions(+), 514 deletions(-)
 create mode 100644 src/providers/ldap/sdap_async_hosts.c
 create mode 100644 src/providers/ldap/sdap_hostid.c
 rename src/providers/{ipa/ipa_hostid.h => ldap/sdap_hostid.h} (55%)

diff --git a/Makefile.am b/Makefile.am
index c947e31..de511c9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -797,7 +797,6 @@ dist_noinst_HEADERS = \
     src/providers/ipa/ipa_dyndns.h \
     src/providers/ipa/ipa_subdomains.h \
     src/providers/ipa/ipa_id.h \
-    src/providers/ipa/ipa_hostid.h \
     src/providers/ipa/ipa_opts.h \
     src/providers/ipa/ipa_srv.h \
     src/providers/ipa/ipa_dn.h \
@@ -3682,11 +3681,13 @@ libsss_ldap_common_la_SOURCES = \
     src/providers/ldap/sdap_async_initgroups_ad.c \
     src/providers/ldap/sdap_async_connection.c \
     src/providers/ldap/sdap_async_netgroups.c \
+    src/providers/ldap/sdap_async_hosts.c \
     src/providers/ldap/sdap_async_services.c \
     src/providers/ldap/sdap_online_check.c \
     src/providers/ldap/sdap_ad_groups.c \
     src/providers/ldap/sdap_child_helpers.c \
     src/providers/ldap/sdap_fd_events.c \
+    src/providers/ldap/sdap_hostid.h \
     src/providers/ldap/sdap_id_op.c \
     src/providers/ldap/sdap_idmap.c \
     src/providers/ldap/sdap_idmap.h \
@@ -3721,6 +3722,10 @@ if BUILD_SYSTEMTAP
 libsss_ldap_common_la_LIBADD += stap_generated_probes.lo
 endif
 
+if BUILD_SSH
+libsss_ldap_common_la_SOURCES += src/providers/ldap/sdap_hostid.c
+endif
+
 if BUILD_SUDO
 libsss_ldap_common_la_SOURCES += \
     src/providers/ldap/sdap_async_sudo.c \
diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml
index 98db5b9..d8b8ce7 100644
--- a/src/man/sssd-ipa.5.xml
+++ b/src/man/sssd-ipa.5.xml
@@ -307,33 +307,23 @@
                 </varlistentry>
 
                 <varlistentry>
-                    <term>ipa_hbac_search_base (string)</term>
+                    <term>ipa_host_search_base (string)</term>
                     <listitem>
                         <para>
-                            Optional. Use the given string as search base for
-                            HBAC related objects.
-                        </para>
-                        <para>
-                            Default: Use base DN
+                            Deprecated. Use ldap_host_search_base instead.
                         </para>
                     </listitem>
                 </varlistentry>
 
                 <varlistentry>
-                    <term>ipa_host_search_base (string)</term>
+                    <term>ipa_hbac_search_base (string)</term>
                     <listitem>
                         <para>
                             Optional. Use the given string as search base for
-                            host objects.
-                        </para>
-                        <para>
-                            See <quote>ldap_search_base</quote> for
-                            information about configuring multiple search
-                            bases.
+                            HBAC related objects.
                         </para>
                         <para>
-                            Default: the value of
-                            <emphasis>ldap_search_base</emphasis>
+                            Default: Use base DN
                         </para>
                     </listitem>
                 </varlistentry>
diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
index 739ae15..9a6bb6f 100644
--- a/src/man/sssd-ldap.5.xml
+++ b/src/man/sssd-ldap.5.xml
@@ -1177,6 +1177,115 @@
                 </varlistentry>
 
                 <varlistentry>
+                    <term>ldap_host_object_class (string)</term>
+                    <listitem>
+                        <para>
+                            The object class of a host entry in LDAP.
+                        </para>
+                        <para>
+                            Default: ipService
+                        </para>
+                    </listitem>
+                </varlistentry>
+
+                <varlistentry>
+                    <term>ldap_host_name (string)</term>
+                    <listitem>
+                        <para>
+                            The LDAP attribute that corresponds to the host's
+                            name.
+                        </para>
+                        <para>
+                            Default: cn
+                        </para>
+                    </listitem>
+                </varlistentry>
+
+                <varlistentry>
+                    <term>ldap_host_fqdn (string)</term>
+                    <listitem>
+                        <para>
+                            The LDAP attribute that corresponds to the host's
+                            fully-qualified domain name.
+                        </para>
+                        <para>
+                            Default: fqdn
+                        </para>
+                    </listitem>
+                </varlistentry>
+
+                <varlistentry>
+                    <term>ldap_host_serverhostname (string)</term>
+                    <listitem>
+                        <para>
+                            The LDAP attribute that corresponds to the host's
+                            name.
+                        </para>
+                        <para>
+                            Default: serverHostname
+                        </para>
+                    </listitem>
+                </varlistentry>
+
+                <varlistentry>
+                    <term>ldap_host_member_of (string)</term>
+                    <listitem>
+                        <para>
+                            The LDAP attribute that lists the host's group
+                            memberships.
+                        </para>
+                        <para>
+                            Default: memberOf
+                        </para>
+                    </listitem>
+                </varlistentry>
+
+                <varlistentry>
+                    <term>ldap_host_search_base (string)</term>
+                    <listitem>
+                        <para>
+                            Optional. Use the given string as search base for
+                            host objects.
+                        </para>
+                        <para>
+                            See <quote>ldap_search_base</quote> for
+                            information about configuring multiple search
+                            bases.
+                        </para>
+                        <para>
+                            Default: the value of
+                            <emphasis>ldap_search_base</emphasis>
+                        </para>
+                    </listitem>
+                </varlistentry>
+
+                <varlistentry condition="with_ssh">
+                    <term>ldap_host_ssh_public_key (string)</term>
+                    <listitem>
+                        <para>
+                            The LDAP attribute that contains the host's SSH
+                            public keys.
+                        </para>
+                        <para>
+                            Default: sshPublicKey
+                        </para>
+                    </listitem>
+                </varlistentry>
+
+                <varlistentry>
+                    <term>ldap_host_uuid (string)</term>
+                    <listitem>
+                        <para>
+                            The LDAP attribute that contains the UUID/GUID of
+                            an LDAP host object.
+                        </para>
+                        <para>
+                            Default: not set
+                        </para>
+                    </listitem>
+                </varlistentry>
+
+                <varlistentry>
                     <term>ldap_service_object_class (string)</term>
                     <listitem>
                         <para>
diff --git a/src/providers/ad/ad_opts.c b/src/providers/ad/ad_opts.c
index fc1dc67..3980aba 100644
--- a/src/providers/ad/ad_opts.c
+++ b/src/providers/ad/ad_opts.c
@@ -72,6 +72,7 @@ struct dp_option ad_def_ldap_opts[] = {
     { "ldap_group_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_group_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING },
     { "ldap_group_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "ldap_host_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_service_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_sudo_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_sudo_full_refresh_interval", DP_OPT_NUMBER, { .number = 21600 }, NULL_NUMBER }, /* 360 mins */
diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
index 6579945..108054d 100644
--- a/src/providers/ipa/ipa_common.c
+++ b/src/providers/ipa/ipa_common.c
@@ -134,9 +134,6 @@ static errno_t ipa_parse_search_base(TALLOC_CTX *mem_ctx,
     case IPA_HBAC_SEARCH_BASE:
         class_name = "IPA_HBAC";
         break;
-    case IPA_HOST_SEARCH_BASE:
-        class_name = "IPA_HOST";
-        break;
     case IPA_SELINUX_SEARCH_BASE:
         class_name = "IPA_SELINUX";
         break;
@@ -333,23 +330,27 @@ int ipa_get_id_options(struct ipa_options *ipa_opts,
                                  &ipa_opts->id->sdom->netgroup_search_bases);
     if (ret != EOK) goto done;
 
-    if (NULL == dp_opt_get_string(ipa_opts->basic,
-                                  IPA_HOST_SEARCH_BASE)) {
-        ret = dp_opt_set_string(ipa_opts->basic, IPA_HOST_SEARCH_BASE,
-                                dp_opt_get_string(ipa_opts->id->basic,
-                                                  SDAP_SEARCH_BASE));
+    if (NULL == dp_opt_get_string(ipa_opts->id->basic,
+                                  SDAP_HOST_SEARCH_BASE)) {
+
+        value = dp_opt_get_string(ipa_opts->basic, IPA_HOST_SEARCH_BASE);
+        if (!value) {
+            value = dp_opt_get_string(ipa_opts->id->basic, SDAP_SEARCH_BASE);
+        }
+
+        ret = dp_opt_set_string(ipa_opts->id->basic, SDAP_HOST_SEARCH_BASE,
+                                value);
         if (ret != EOK) {
             goto done;
         }
 
         DEBUG(SSSDBG_CONF_SETTINGS, "Option %s set to %s\n",
-                  ipa_opts->basic[IPA_HOST_SEARCH_BASE].opt_name,
-                  dp_opt_get_string(ipa_opts->basic,
-                                    IPA_HOST_SEARCH_BASE));
+              ipa_opts->id->basic[SDAP_HOST_SEARCH_BASE].opt_name,
+              value);
     }
-    ret = ipa_parse_search_base(ipa_opts->basic, ipa_opts->basic,
-                                IPA_HOST_SEARCH_BASE,
-                                &ipa_opts->host_search_bases);
+    ret = sdap_parse_search_base(ipa_opts->id->basic, ipa_opts->id->basic,
+                                SDAP_HOST_SEARCH_BASE,
+                                &ipa_opts->id->sdom->host_search_bases);
     if (ret != EOK) goto done;
 
     if (NULL == dp_opt_get_string(ipa_opts->basic,
@@ -566,8 +567,8 @@ int ipa_get_id_options(struct ipa_options *ipa_opts,
     ret = sdap_get_map(ipa_opts->id,
                        cdb, conf_path,
                        ipa_host_map,
-                       IPA_OPTS_HOST,
-                       &ipa_opts->host_map);
+                       SDAP_OPTS_HOST,
+                       &ipa_opts->id->host_map);
     if (ret != EOK) {
         goto done;
     }
diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h
index add9df8..14a2c6d 100644
--- a/src/providers/ipa/ipa_common.h
+++ b/src/providers/ipa/ipa_common.h
@@ -41,8 +41,8 @@ enum ipa_basic_opt {
     IPA_SERVER,
     IPA_BACKUP_SERVER,
     IPA_HOSTNAME,
+    IPA_HOST_SEARCH_BASE, /* only used if ldap_host_search_base is not set */
     IPA_HBAC_SEARCH_BASE,
-    IPA_HOST_SEARCH_BASE,
     IPA_SELINUX_SEARCH_BASE,
     IPA_SUBDOMAINS_SEARCH_BASE,
     IPA_MASTER_DOMAIN_SEARCH_BASE,
@@ -74,18 +74,6 @@ enum ipa_netgroup_attrs {
     IPA_OPTS_NETGROUP /* attrs counter */
 };
 
-enum ipa_host_attrs {
-    IPA_OC_HOST = 0,
-    IPA_AT_HOST_NAME,
-    IPA_AT_HOST_FQDN,
-    IPA_AT_HOST_SERVERHOSTNAME,
-    IPA_AT_HOST_MEMBER_OF,
-    IPA_AT_HOST_SSH_PUBLIC_KEY,
-    IPA_AT_HOST_UUID,
-
-    IPA_OPTS_HOST /* attrs counter */
-};
-
 enum ipa_hostgroup_attrs {
     IPA_OC_HOSTGROUP = 0,
     IPA_AT_HOSTGROUP_NAME,
@@ -205,13 +193,11 @@ struct ipa_id_ctx {
 struct ipa_options {
     struct dp_option *basic;
 
-    struct sdap_attr_map *host_map;
     struct sdap_attr_map *hostgroup_map;
     struct sdap_attr_map *selinuxuser_map;
     struct sdap_attr_map *view_map;
     struct sdap_attr_map *override_map;
 
-    struct sdap_search_base **host_search_bases;
     struct sdap_search_base **hbac_search_bases;
     struct sdap_search_base **selinux_search_bases;
     struct sdap_search_base **subdomains_search_bases;
@@ -260,6 +246,11 @@ int ipa_get_autofs_options(struct ipa_options *ipa_opts,
 errno_t ipa_get_dyndns_options(struct be_ctx *be_ctx,
                                struct ipa_options *ctx);
 
+errno_t ipa_hostid_init(TALLOC_CTX *mem_ctx,
+                        struct be_ctx *be_ctx,
+                        struct ipa_id_ctx *id_ctx,
+                        struct dp_method *dp_methods);
+
 errno_t ipa_autofs_init(TALLOC_CTX *mem_ctx,
                         struct be_ctx *be_ctx,
                         struct ipa_id_ctx *id_ctx,
diff --git a/src/providers/ipa/ipa_hostid.c b/src/providers/ipa/ipa_hostid.c
index 87a3616..891536f 100644
--- a/src/providers/ipa/ipa_hostid.c
+++ b/src/providers/ipa/ipa_hostid.c
@@ -1,8 +1,8 @@
 /*
     Authors:
-        Jan Cholasta <jchol...@redhat.com>
+        Hristo Venev <hri...@venev.name>
 
-    Copyright (C) 2012 Red Hat
+    Copyright (C) 2017 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
@@ -18,298 +18,13 @@
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "util/util.h"
-#include "util/crypto/sss_crypto.h"
-#include "db/sysdb_ssh.h"
-#include "providers/ldap/ldap_common.h"
 #include "providers/ipa/ipa_common.h"
-#include "providers/ipa/ipa_hostid.h"
-#include "providers/ipa/ipa_hosts.h"
+#include "providers/ldap/sdap_hostid.h"
 
-struct hosts_get_state {
-    struct tevent_context *ev;
-    struct ipa_hostid_ctx *ctx;
-    struct sdap_id_op *op;
-    struct sss_domain_info *domain;
-    const char *name;
-    const char *alias;
-
-    size_t count;
-    struct sysdb_attrs **hosts;
-    int dp_error;
-};
-
-static errno_t
-hosts_get_retry(struct tevent_req *req);
-static void
-hosts_get_connect_done(struct tevent_req *subreq);
-static void
-hosts_get_done(struct tevent_req *subreq);
-
-struct tevent_req *
-hosts_get_send(TALLOC_CTX *memctx,
-               struct tevent_context *ev,
-               struct ipa_hostid_ctx *hostid_ctx,
-               const char *name,
-               const char *alias)
-{
-    struct tevent_req *req;
-    struct hosts_get_state *state;
-    struct sdap_id_ctx *ctx;
-    errno_t ret;
-
-    ctx = hostid_ctx->sdap_id_ctx;
-
-    req = tevent_req_create(memctx, &state, struct hosts_get_state);
-    if (!req) return NULL;
-
-    state->ev = ev;
-    state->ctx = hostid_ctx;
-    state->dp_error = DP_ERR_FATAL;
-
-    state->op = sdap_id_op_create(state, ctx->conn->conn_cache);
-    if (!state->op) {
-        DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
-        ret = ENOMEM;
-        goto fail;
-    }
-
-    state->domain = ctx->be->domain;
-    state->name = name;
-    state->alias = alias;
-
-    ret = hosts_get_retry(req);
-    if (ret != EOK) {
-        goto fail;
-    }
-
-    return req;
-
-fail:
-    tevent_req_error(req, ret);
-    tevent_req_post(req, ev);
-    return req;
-}
-
-static errno_t
-hosts_get_retry(struct tevent_req *req)
-{
-    struct hosts_get_state *state = tevent_req_data(req,
-                                                    struct hosts_get_state);
-    struct tevent_req *subreq;
-    errno_t ret = EOK;
-
-    subreq = sdap_id_op_connect_send(state->op, state, &ret);
-    if (!subreq) {
-        return ret;
-    }
-
-    tevent_req_set_callback(subreq, hosts_get_connect_done, req);
-    return EOK;
-}
-
-static void
-hosts_get_connect_done(struct tevent_req *subreq)
-{
-    struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                      struct tevent_req);
-    struct hosts_get_state *state = tevent_req_data(req,
-                                                    struct hosts_get_state);
-    int dp_error = DP_ERR_FATAL;
-    errno_t ret;
-
-    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;
-    }
-
-    subreq = ipa_host_info_send(state, state->ev,
-                                sdap_id_op_handle(state->op),
-                                state->ctx->sdap_id_ctx->opts, state->name,
-                                state->ctx->ipa_opts->host_map, NULL,
-                                state->ctx->host_search_bases);
-    if (!subreq) {
-        tevent_req_error(req, ENOMEM);
-        return;
-    }
-    tevent_req_set_callback(subreq, hosts_get_done, req);
-}
-
-static void
-hosts_get_done(struct tevent_req *subreq)
-{
-    struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                      struct tevent_req);
-    struct hosts_get_state *state = tevent_req_data(req,
-                                                    struct hosts_get_state);
-    int dp_error = DP_ERR_FATAL;
-    errno_t ret;
-    struct sysdb_attrs *attrs;
-    time_t now = time(NULL);
-
-    ret = ipa_host_info_recv(subreq, state,
-                             &state->count, &state->hosts,
-                             NULL, NULL);
-    talloc_zfree(subreq);
-
-    ret = sdap_id_op_done(state->op, ret, &dp_error);
-    if (dp_error == DP_ERR_OK && ret != EOK) {
-        /* retry */
-        ret = hosts_get_retry(req);
-        if (ret != EOK) {
-            goto done;
-        }
-        return;
-    }
-
-    if (ret != EOK && ret != ENOENT) {
-        goto done;
-    }
-
-    if (state->count == 0) {
-        DEBUG(SSSDBG_OP_FAILURE,
-              "No host with name [%s] found.\n", state->name);
-
-        ret = sysdb_delete_ssh_host(state->domain, state->name);
-        if (ret != EOK && ret != ENOENT) {
-            goto done;
-        }
-
-        ret = EINVAL;
-        goto done;
-    }
-
-    if (state->count > 1) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "Found more than one host with name [%s].\n", state->name);
-        ret = EINVAL;
-        goto done;
-    }
-
-    attrs = sysdb_new_attrs(state);
-    if (!attrs) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    /* we are interested only in the host keys */
-    ret = sysdb_attrs_copy_values(state->hosts[0], attrs, SYSDB_SSH_PUBKEY);
-    if (ret != EOK) {
-        goto done;
-    }
-
-    ret = sysdb_store_ssh_host(state->domain, state->name, state->alias,
-                               state->domain->ssh_host_timeout, now, attrs);
-    if (ret != EOK) {
-        goto done;
-    }
-
-    dp_error = DP_ERR_OK;
-
-done:
-    state->dp_error = dp_error;
-    if (ret == EOK) {
-        tevent_req_done(req);
-    } else {
-        tevent_req_error(req, ret);
-    }
-}
-
-static errno_t
-hosts_get_recv(struct tevent_req *req,
-               int *dp_error_out)
-{
-    struct hosts_get_state *state = tevent_req_data(req,
-                                                    struct hosts_get_state);
-
-    if (dp_error_out) {
-        *dp_error_out = state->dp_error;
-    }
-
-    TEVENT_REQ_RETURN_ON_ERROR(req);
-
-    return EOK;
-}
-
-struct ipa_hostid_handler_state {
-    struct dp_reply_std reply;
-};
-
-static void ipa_hostid_handler_done(struct tevent_req *subreq);
-
-struct tevent_req *
-ipa_hostid_handler_send(TALLOC_CTX *mem_ctx,
-                       struct ipa_hostid_ctx *hostid_ctx,
-                       struct dp_hostid_data *data,
-                       struct dp_req_params *params)
-{
-    struct ipa_hostid_handler_state *state;
-    struct tevent_req *subreq;
-    struct tevent_req *req;
-    errno_t ret;
-
-    req = tevent_req_create(mem_ctx, &state, struct ipa_hostid_handler_state);
-    if (req == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
-        return NULL;
-    }
-
-    subreq = hosts_get_send(state, params->ev, hostid_ctx,
-                            data->name, data->alias);
-    if (subreq == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to send request\n");
-        ret = ENOMEM;
-        goto immediately;
-    }
-
-    tevent_req_set_callback(subreq, ipa_hostid_handler_done, req);
-
-    return req;
-
-immediately:
-    dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ret, NULL);
-
-    /* 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_hostid_handler_done(struct tevent_req *subreq)
+errno_t ipa_hostid_init(TALLOC_CTX *mem_ctx,
+                        struct be_ctx *be_ctx,
+                        struct ipa_id_ctx *id_ctx,
+                        struct dp_method *dp_methods)
 {
-    struct ipa_hostid_handler_state *state;
-    struct tevent_req *req;
-    int dp_error;
-    errno_t ret;
-
-    req = tevent_req_callback_data(subreq, struct tevent_req);
-    state = tevent_req_data(req, struct ipa_hostid_handler_state);
-
-    ret = hosts_get_recv(subreq, &dp_error);
-    talloc_zfree(subreq);
-
-    /* TODO For backward compatibility we always return EOK to DP now. */
-    dp_reply_std_set(&state->reply, dp_error, ret, NULL);
-    tevent_req_done(req);
-}
-
-errno_t
-ipa_hostid_handler_recv(TALLOC_CTX *mem_ctx,
-                       struct tevent_req *req,
-                       struct dp_reply_std *data)
-{
-    struct ipa_hostid_handler_state *state = NULL;
-
-    state = tevent_req_data(req, struct ipa_hostid_handler_state);
-
-    TEVENT_REQ_RETURN_ON_ERROR(req);
-
-    *data = state->reply;
-
-    return EOK;
+    return sdap_hostid_init(mem_ctx, be_ctx, id_ctx->sdap_id_ctx, dp_methods);
 }
diff --git a/src/providers/ipa/ipa_hosts.c b/src/providers/ipa/ipa_hosts.c
index 5966e3c..2ca815f 100644
--- a/src/providers/ipa/ipa_hosts.c
+++ b/src/providers/ipa/ipa_hosts.c
@@ -21,18 +21,15 @@
 */
 
 #include "util/util.h"
-#include "db/sysdb.h"
 #include "providers/ldap/sdap_async.h"
 #include "providers/ipa/ipa_hosts.h"
 #include "providers/ipa/ipa_common.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_attr_map *host_map;
     struct sdap_attr_map *hostgroup_map;
 
     struct sdap_search_base **search_bases;
@@ -49,21 +46,16 @@ struct ipa_host_state {
 
     size_t hostgroup_count;
     struct sysdb_attrs **hostgroups;
-    struct sdap_attr_map_info *ipa_hostgroup_map;
 };
 
 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);
+static void
+ipa_hostgroup_info_done(struct tevent_req *subreq);
 
 /**
  * hostname == NULL -> look up all hosts / host groups
@@ -81,9 +73,8 @@ ipa_host_info_send(TALLOC_CTX *mem_ctx,
                    struct sdap_attr_map *hostgroup_map,
                    struct sdap_search_base **search_bases)
 {
-    errno_t ret;
     struct ipa_host_state *state;
-    struct tevent_req *req;
+    struct tevent_req *req, *subreq;
 
     req = tevent_req_create(mem_ctx, &state, struct ipa_host_state);
     if (req == NULL) {
@@ -97,85 +88,16 @@ ipa_host_info_send(TALLOC_CTX *mem_ctx,
     state->search_bases = search_bases;
     state->search_base_iter = 0;
     state->cur_filter = NULL;
-    state->host_map = host_map;
     state->hostgroup_map = hostgroup_map;
 
-    ret = build_attrs_from_map(state, host_map, IPA_OPTS_HOST,
-                               NULL, &state->attrs, NULL);
-    if (ret != EOK) {
-        goto immediate;
-    }
-
-    if (hostname == NULL) {
-        state->host_filter = talloc_asprintf(state, "(objectClass=%s)",
-                                             host_map[IPA_OC_HOST].name);
-    } else {
-        state->host_filter = talloc_asprintf(state, "(&(objectClass=%s)(%s=%s))",
-                                             host_map[IPA_OC_HOST].name,
-                                             host_map[IPA_AT_HOST_FQDN].name,
-                                             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_combine_filters(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, state->host_map,
-                                   IPA_OPTS_HOST,
-                                   dp_opt_get_int(state->opts->basic,
-                                                  SDAP_ENUM_SEARCH_TIMEOUT),
-                                   true);
+    subreq = sdap_host_info_send(mem_ctx, ev, sh, opts, hostname, host_map, search_bases);
     if (subreq == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Error requesting host info\n");
-        talloc_zfree(state->cur_filter);
-        return EIO;
+        talloc_zfree(req);
+        return NULL;
     }
     tevent_req_set_callback(subreq, ipa_host_info_done, req);
 
-    return EAGAIN;
+    return req;
 }
 
 static void
@@ -187,38 +109,27 @@ ipa_host_info_done(struct tevent_req *subreq)
     struct ipa_host_state *state =
             tevent_req_data(req, struct ipa_host_state);
     const char *host_dn;
+    struct sdap_attr_map_info *maps;
+    const int num_maps = 1;
 
-    ret = sdap_get_generic_recv(subreq, state,
-                                &state->host_count,
-                                &state->hosts);
+    ret = sdap_host_info_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);
-        }
+    ret = build_attrs_from_map(state, state->hostgroup_map,
+                               IPA_OPTS_HOSTGROUP, NULL,
+                               &state->attrs, NULL);
+    if (ret != EOK) {
+        tevent_req_error(req, ret);
         return;
     }
 
     if (state->hostgroup_map) {
-        talloc_free(state->attrs);
-        ret = build_attrs_from_map(state, state->hostgroup_map,
-                                   IPA_OPTS_HOSTGROUP, NULL,
-                                   &state->attrs, NULL);
-        if (ret != EOK) {
-            tevent_req_error(req, ret);
-            return;
-        }
-
         /* Look up host groups */
         if (state->hostname == NULL) {
             talloc_zfree(state->host_filter);
@@ -240,14 +151,6 @@ ipa_host_info_done(struct tevent_req *subreq)
                 return;
             }
         } else {
-            state->ipa_hostgroup_map = talloc_zero(state, struct sdap_attr_map_info);
-            if (state->ipa_hostgroup_map == NULL) {
-                tevent_req_error(req, ENOMEM);
-                return;
-            }
-            state->ipa_hostgroup_map->map = state->hostgroup_map;
-            state->ipa_hostgroup_map->num_attrs = IPA_OPTS_HOSTGROUP;
-
             ret = sysdb_attrs_get_string(state->hosts[0], SYSDB_ORIG_DN, &host_dn);
             if (ret != EOK) {
                 tevent_req_error(req, ret);
@@ -260,14 +163,24 @@ ipa_host_info_done(struct tevent_req *subreq)
                 return;
             }
 
+            maps = talloc_array(state, struct sdap_attr_map_info, num_maps+1);
+            if (maps == NULL) {
+                tevent_req_error(req, ENOMEM);
+                return;
+            }
+            maps[0].map = state->hostgroup_map;
+            maps[0].num_attrs = IPA_OPTS_HOSTGROUP;
+            maps[1].map = NULL;
+
             subreq = sdap_deref_search_send(state, state->ev, state->opts, state->sh,
                                             host_dn,
                                             state->hostgroup_map[IPA_AT_HOSTGROUP_MEMBER_OF].name,
                                             state->attrs,
-                                            1, state->ipa_hostgroup_map,
+                                            num_maps, maps,
                                             dp_opt_get_int(state->opts->basic,
                                                            SDAP_ENUM_SEARCH_TIMEOUT));
             if (subreq == NULL) {
+                talloc_free(maps);
                 DEBUG(SSSDBG_CRIT_FAILURE, "Error requesting host info\n");
                 tevent_req_error(req, EIO);
                 return;
@@ -275,13 +188,12 @@ ipa_host_info_done(struct tevent_req *subreq)
             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 ipa_host_state *state)
 {
     struct sdap_search_base *base;
     struct tevent_req *subreq;
@@ -437,7 +349,6 @@ errno_t ipa_host_info_recv(struct tevent_req *req,
                            size_t *hostgroup_count,
                            struct sysdb_attrs ***hostgroups)
 {
-    size_t c;
     struct ipa_host_state *state =
             tevent_req_data(req, struct ipa_host_state);
 
@@ -445,10 +356,6 @@ errno_t ipa_host_info_recv(struct tevent_req *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]);
-    }
 
     if (hostgroup_count) *hostgroup_count = state->hostgroup_count;
     if (hostgroups) *hostgroups = talloc_steal(mem_ctx, state->hostgroups);
diff --git a/src/providers/ipa/ipa_hosts.h b/src/providers/ipa/ipa_hosts.h
index a1ea7a2..aed16b1 100644
--- a/src/providers/ipa/ipa_hosts.h
+++ b/src/providers/ipa/ipa_hosts.h
@@ -22,6 +22,7 @@
 
 #ifndef IPA_HOSTS_H_
 #define IPA_HOSTS_H_
+#include "providers/ipa/ipa_common.h"
 
 struct tevent_req *
 ipa_host_info_send(TALLOC_CTX *mem_ctx,
@@ -41,4 +42,4 @@ ipa_host_info_recv(struct tevent_req *req,
                    size_t *hostgroup_count,
                    struct sysdb_attrs ***hostgroups);
 
-#endif /* IPA_HOSTS_H_ */
+#endif /* IPA_HOSTS_H */
diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c
index 7dec4d1..9922228 100644
--- a/src/providers/ipa/ipa_init.c
+++ b/src/providers/ipa/ipa_init.c
@@ -34,7 +34,6 @@
 #include "providers/ipa/ipa_id.h"
 #include "providers/ipa/ipa_auth.h"
 #include "providers/ipa/ipa_access.h"
-#include "providers/ipa/ipa_hostid.h"
 #include "providers/ipa/ipa_dyndns.h"
 #include "providers/ipa/ipa_selinux.h"
 #include "providers/ldap/sdap_access.h"
@@ -783,9 +782,9 @@ errno_t sssm_ipa_access_init(TALLOC_CTX *mem_ctx,
     }
 
     access_ctx->sdap_ctx = id_ctx->sdap_id_ctx;
-    access_ctx->host_map = id_ctx->ipa_options->host_map;
+    access_ctx->host_map = id_ctx->ipa_options->id->host_map;
     access_ctx->hostgroup_map = id_ctx->ipa_options->hostgroup_map;
-    access_ctx->host_search_bases = id_ctx->ipa_options->host_search_bases;
+    access_ctx->host_search_bases = id_ctx->ipa_options->id->sdom->host_search_bases;
     access_ctx->hbac_search_bases = id_ctx->ipa_options->hbac_search_bases;
 
     ret = dp_copy_options(access_ctx, id_ctx->ipa_options->basic,
@@ -842,7 +841,7 @@ errno_t sssm_ipa_selinux_init(TALLOC_CTX *mem_ctx,
 
     selinux_ctx->id_ctx = init_ctx->id_ctx;
     selinux_ctx->hbac_search_bases = opts->hbac_search_bases;
-    selinux_ctx->host_search_bases = opts->host_search_bases;
+    selinux_ctx->host_search_bases = opts->id->sdom->host_search_bases;
     selinux_ctx->selinux_search_bases = opts->selinux_search_bases;
 
     dp_set_method(dp_methods, DPM_SELINUX_HANDLER,
@@ -863,26 +862,13 @@ errno_t sssm_ipa_hostid_init(TALLOC_CTX *mem_ctx,
                              struct dp_method *dp_methods)
 {
 #ifdef BUILD_SSH
-    struct ipa_hostid_ctx *hostid_ctx;
     struct ipa_init_ctx *init_ctx;
 
+    DEBUG(SSSDBG_TRACE_INTERNAL, "Initializing IPA host handler\n");
     init_ctx = talloc_get_type(module_data, struct ipa_init_ctx);
 
-    hostid_ctx = talloc_zero(mem_ctx, struct ipa_hostid_ctx);
-    if (hostid_ctx == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
-        return ENOMEM;
-    }
-
-    hostid_ctx->sdap_id_ctx = init_ctx->id_ctx->sdap_id_ctx;
-    hostid_ctx->host_search_bases = init_ctx->options->host_search_bases;
-    hostid_ctx->ipa_opts = init_ctx->options;
+    return ipa_hostid_init(mem_ctx, be_ctx, init_ctx->id_ctx, dp_methods);
 
-    dp_set_method(dp_methods, DPM_HOSTID_HANDLER,
-                  ipa_hostid_handler_send, ipa_hostid_handler_recv, hostid_ctx,
-                  struct ipa_hostid_ctx, struct dp_hostid_data, struct dp_reply_std);
-
-    return EOK;
 #else
     DEBUG(SSSDBG_MINOR_FAILURE, "HostID init handler called but SSSD is "
                                 "built without SSH support, ignoring\n");
diff --git a/src/providers/ipa/ipa_netgroups.c b/src/providers/ipa/ipa_netgroups.c
index 17b11af..8991313 100644
--- a/src/providers/ipa/ipa_netgroups.c
+++ b/src/providers/ipa/ipa_netgroups.c
@@ -516,7 +516,7 @@ static int ipa_netgr_fetch_hosts(struct ipa_get_netgroups_state *state,
     int ret;
     struct sdap_search_base **bases;
 
-    bases = state->ipa_opts->host_search_bases;
+    bases = state->ipa_opts->id->sdom->host_search_bases;
     if (bases[state->host_base_iter] == NULL) {
         return ENOENT;
     }
@@ -525,12 +525,12 @@ static int ipa_netgr_fetch_hosts(struct ipa_get_netgroups_state *state,
     filter = talloc_asprintf(state, "(&%s%s(objectclass=%s))",
                              state->filter,
                              base_filter?base_filter:"",
-                             state->ipa_opts->host_map[IPA_OC_HOST].name);
+                             state->ipa_opts->id->host_map[SDAP_OC_HOST].name);
     if (filter == NULL)
         return ENOMEM;
 
-    ret = build_attrs_from_map(state, state->ipa_opts->host_map,
-                               IPA_OPTS_HOST, NULL, &attrs, NULL);
+    ret = build_attrs_from_map(state, state->ipa_opts->id->host_map,
+                               SDAP_OPTS_HOST, NULL, &attrs, NULL);
     if (ret != EOK) {
         talloc_free(filter);
         return ret;
@@ -539,8 +539,8 @@ static int ipa_netgr_fetch_hosts(struct ipa_get_netgroups_state *state,
     subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
                                    bases[state->host_base_iter]->basedn,
                                    bases[state->host_base_iter]->scope,
-                                   filter, attrs, state->ipa_opts->host_map,
-                                   IPA_OPTS_HOST, state->timeout, true);
+                                   filter, attrs, state->ipa_opts->id->host_map,
+                                   SDAP_OPTS_HOST, state->timeout, true);
 
     state->current_entity = ENTITY_HOST;
     if (subreq == NULL) {
@@ -918,7 +918,7 @@ static int ipa_netgr_process_all(struct ipa_get_netgroups_state *state)
         DEBUG(SSSDBG_TRACE_ALL, "Extracting host members of netgroup %d\n", i);
         ret = extract_members(state, state->netgroups[i],
                               SYSDB_ORIG_MEMBER_HOST,
-                              state->ipa_opts->host_map[IPA_AT_HOST_MEMBER_OF].sys_name,
+                              state->ipa_opts->id->host_map[SDAP_AT_HOST_MEMBER_OF].sys_name,
                               state->new_hosts,
                               &hosts, &hosts_count);
         if (ret != EOK) {
diff --git a/src/providers/ipa/ipa_opts.c b/src/providers/ipa/ipa_opts.c
index f9f3a2a..80e6801 100644
--- a/src/providers/ipa/ipa_opts.c
+++ b/src/providers/ipa/ipa_opts.c
@@ -81,6 +81,7 @@ struct dp_option ipa_def_ldap_opts[] = {
     { "ldap_group_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_group_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING },
     { "ldap_group_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "ldap_host_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_service_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_sudo_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_sudo_full_refresh_interval", DP_OPT_NUMBER, { .number = 21600 }, NULL_NUMBER },
diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c
index 6d0778d..3e8eb22 100644
--- a/src/providers/ipa/ipa_selinux.c
+++ b/src/providers/ipa/ipa_selinux.c
@@ -978,7 +978,7 @@ static void ipa_get_selinux_connect_done(struct tevent_req *subreq)
                                 sdap_id_op_handle(state->op),
                                 id_ctx->sdap_id_ctx->opts,
                                 hostname,
-                                id_ctx->ipa_options->host_map,
+                                id_ctx->ipa_options->id->host_map,
                                 NULL,
                                 state->selinux_ctx->host_search_bases);
     if (subreq == NULL) {
diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
index ef348ad..3369f28 100644
--- a/src/providers/ipa/ipa_subdomains.c
+++ b/src/providers/ipa/ipa_subdomains.c
@@ -1571,8 +1571,8 @@ ipa_subdomains_view_name_send(TALLOC_CTX *mem_ctx,
     maps->num_attrs = IPA_OPTS_VIEW;
 
     filter = talloc_asprintf(state, "(&(objectClass=%s)(%s=%s))",
-                        ipa_options->host_map[IPA_OC_HOST].name,
-                        ipa_options->host_map[IPA_AT_HOST_FQDN].name,
+                        ipa_options->id->host_map[SDAP_OC_HOST].name,
+                        ipa_options->id->host_map[SDAP_AT_HOST_FQDN].name,
                         dp_opt_get_string(ipa_options->basic, IPA_HOSTNAME));
     if (filter == NULL) {
         ret = ENOMEM;
@@ -2418,7 +2418,7 @@ errno_t ipa_subdomains_init(TALLOC_CTX *mem_ctx,
     sd_ctx->search_bases = ipa_options->subdomains_search_bases;
     sd_ctx->master_search_bases = ipa_options->master_domain_search_bases;
     sd_ctx->ranges_search_bases = ipa_options->ranges_search_bases;
-    sd_ctx->host_search_bases = ipa_options->host_search_bases;
+    sd_ctx->host_search_bases = ipa_options->id->sdom->host_search_bases;
 
     dp_set_method(dp_methods, DPM_DOMAINS_HANDLER,
                   ipa_subdomains_handler_send, ipa_subdomains_handler_recv, sd_ctx,
diff --git a/src/providers/ipa/ipa_sudo_async.c b/src/providers/ipa/ipa_sudo_async.c
index 9ed1218..4a2fb4d 100644
--- a/src/providers/ipa/ipa_sudo_async.c
+++ b/src/providers/ipa/ipa_sudo_async.c
@@ -978,9 +978,9 @@ ipa_sudo_refresh_connect_done(struct tevent_req *subreq)
 
     subreq = ipa_host_info_send(state, state->ev,
                                 state->sh, state->sdap_opts, hostname,
-                                state->ipa_opts->host_map,
+                                state->ipa_opts->id->host_map,
                                 state->ipa_opts->hostgroup_map,
-                                state->ipa_opts->host_search_bases);
+                                state->ipa_opts->id->sdom->host_search_bases);
     if (subreq == NULL) {
         state->dp_error = DP_ERR_FATAL;
         tevent_req_error(req, ENOMEM);
@@ -1023,7 +1023,7 @@ ipa_sudo_refresh_host_done(struct tevent_req *subreq)
                                  state->sudo_ctx, host,
                                  state->sdap_opts->user_map,
                                  state->sdap_opts->group_map,
-                                 state->ipa_opts->host_map,
+                                 state->ipa_opts->id->host_map,
                                  state->ipa_opts->hostgroup_map, state->sh,
                                  state->cmdgroups_filter, state->search_filter);
     if (subreq == NULL) {
diff --git a/src/providers/ipa/ipa_sudo_conversion.c b/src/providers/ipa/ipa_sudo_conversion.c
index f6d17d8..5d6febb 100644
--- a/src/providers/ipa/ipa_sudo_conversion.c
+++ b/src/providers/ipa/ipa_sudo_conversion.c
@@ -43,7 +43,7 @@
 
 #define MATCHRDN_USER(map)      (map)[SDAP_AT_USER_NAME].name, "cn", "users", "cn", "accounts"
 #define MATCHRDN_GROUP(map)     (map)[SDAP_AT_GROUP_NAME].name, "cn", "groups", "cn", "accounts"
-#define MATCHRDN_HOST(map)      (map)[IPA_AT_HOST_FQDN].name, "cn", "computers", "cn", "accounts"
+#define MATCHRDN_HOST(map)      (map)[SDAP_AT_HOST_FQDN].name, "cn", "computers", "cn", "accounts"
 #define MATCHRDN_HOSTGROUP(map) (map)[IPA_AT_HOSTGROUP_NAME].name, "cn", "hostgroups", "cn", "accounts"
 
 struct ipa_sudo_conv {
diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c
index b7102ad..7433701 100644
--- a/src/providers/ldap/ldap_init.c
+++ b/src/providers/ldap/ldap_init.c
@@ -26,6 +26,7 @@
 #include "providers/ldap/ldap_common.h"
 #include "providers/ldap/sdap_async_private.h"
 #include "providers/ldap/sdap_access.h"
+#include "providers/ldap/sdap_hostid.h"
 #include "providers/ldap/sdap_sudo.h"
 #include "providers/ldap/sdap_autofs.h"
 #include "providers/ldap/sdap_idmap.h"
@@ -618,6 +619,26 @@ errno_t sssm_ldap_access_init(TALLOC_CTX *mem_ctx,
     return ret;
 }
 
+errno_t sssm_ldap_hostid_init(TALLOC_CTX *mem_ctx,
+                             struct be_ctx *be_ctx,
+                             void *module_data,
+                             struct dp_method *dp_methods)
+{
+#ifdef BUILD_SSH
+    struct ldap_init_ctx *init_ctx;
+
+    DEBUG(SSSDBG_TRACE_INTERNAL, "Initializing LDAP host handler\n");
+    init_ctx = talloc_get_type(module_data, struct ldap_init_ctx);
+
+    return sdap_hostid_init(mem_ctx, be_ctx, init_ctx->id_ctx, dp_methods);
+
+#else
+    DEBUG(SSSDBG_MINOR_FAILURE, "HostID init handler called but SSSD is "
+                                "built without SSH support, ignoring\n");
+    return EOK;
+#endif
+}
+
 errno_t sssm_ldap_autofs_init(TALLOC_CTX *mem_ctx,
                               struct be_ctx *be_ctx,
                               void *module_data,
diff --git a/src/providers/ldap/ldap_options.c b/src/providers/ldap/ldap_options.c
index eb4e177..ccc1a2c 100644
--- a/src/providers/ldap/ldap_options.c
+++ b/src/providers/ldap/ldap_options.c
@@ -33,6 +33,7 @@ int ldap_get_options(TALLOC_CTX *memctx,
     struct sdap_attr_map *default_user_map;
     struct sdap_attr_map *default_group_map;
     struct sdap_attr_map *default_netgroup_map;
+    struct sdap_attr_map *default_host_map;
     struct sdap_attr_map *default_service_map;
     struct sdap_options *opts;
     char *schema;
@@ -50,6 +51,7 @@ int ldap_get_options(TALLOC_CTX *memctx,
     const int search_base_options[] = { SDAP_USER_SEARCH_BASE,
                                         SDAP_GROUP_SEARCH_BASE,
                                         SDAP_NETGROUP_SEARCH_BASE,
+                                        SDAP_HOST_SEARCH_BASE,
                                         SDAP_SERVICE_SEARCH_BASE,
                                         -1 };
 
@@ -116,6 +118,12 @@ int ldap_get_options(TALLOC_CTX *memctx,
                                  &opts->sdom->netgroup_search_bases);
     if (ret != EOK && ret != ENOENT) goto done;
 
+    /* Netgroup search */
+    ret = sdap_parse_search_base(opts, opts->basic,
+                                 SDAP_HOST_SEARCH_BASE,
+                                 &opts->sdom->host_search_bases);
+    if (ret != EOK && ret != ENOENT) goto done;
+
     /* Service search */
     ret = sdap_parse_search_base(opts, opts->basic,
                                  SDAP_SERVICE_SEARCH_BASE,
@@ -214,6 +222,7 @@ int ldap_get_options(TALLOC_CTX *memctx,
         default_user_map = rfc2307_user_map;
         default_group_map = rfc2307_group_map;
         default_netgroup_map = netgroup_map;
+        default_host_map = host_map;
         default_service_map = service_map;
     } else
     if (strcasecmp(schema, "rfc2307bis") == 0) {
@@ -222,6 +231,7 @@ int ldap_get_options(TALLOC_CTX *memctx,
         default_user_map = rfc2307bis_user_map;
         default_group_map = rfc2307bis_group_map;
         default_netgroup_map = netgroup_map;
+        default_host_map = host_map;
         default_service_map = service_map;
     } else
     if (strcasecmp(schema, "IPA") == 0) {
@@ -230,6 +240,7 @@ int ldap_get_options(TALLOC_CTX *memctx,
         default_user_map = rfc2307bis_user_map;
         default_group_map = rfc2307bis_group_map;
         default_netgroup_map = netgroup_map;
+        default_host_map = host_map;
         default_service_map = service_map;
     } else
     if (strcasecmp(schema, "AD") == 0) {
@@ -238,6 +249,7 @@ int ldap_get_options(TALLOC_CTX *memctx,
         default_user_map = gen_ad2008r2_user_map;
         default_group_map = gen_ad2008r2_group_map;
         default_netgroup_map = netgroup_map;
+        default_host_map = host_map;
         default_service_map = service_map;
     } else {
         DEBUG(SSSDBG_FATAL_FAILURE, "Unrecognized schema type: %s\n", schema);
@@ -285,6 +297,14 @@ int ldap_get_options(TALLOC_CTX *memctx,
     }
 
     ret = sdap_get_map(opts, cdb, conf_path,
+                       default_host_map,
+                       SDAP_OPTS_HOST,
+                       &opts->host_map);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    ret = sdap_get_map(opts, cdb, conf_path,
                        default_service_map,
                        SDAP_OPTS_SERVICES,
                        &opts->service_map);
@@ -596,6 +616,9 @@ errno_t sdap_parse_search_base(TALLOC_CTX *mem_ctx,
     case SDAP_NETGROUP_SEARCH_BASE:
         class_name = "NETGROUP";
         break;
+    case SDAP_HOST_SEARCH_BASE:
+        class_name = "HOST";
+        break;
     case SDAP_SUDO_SEARCH_BASE:
         class_name = "SUDO";
         break;
diff --git a/src/providers/ldap/ldap_opts.c b/src/providers/ldap/ldap_opts.c
index c6efe33..529a603 100644
--- a/src/providers/ldap/ldap_opts.c
+++ b/src/providers/ldap/ldap_opts.c
@@ -45,6 +45,7 @@ struct dp_option default_basic_opts[] = {
     { "ldap_group_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_group_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING },
     { "ldap_group_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "ldap_host_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_service_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_sudo_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ldap_sudo_full_refresh_interval", DP_OPT_NUMBER, { .number = 21600 }, NULL_NUMBER }, /* 360 mins */
@@ -325,6 +326,17 @@ struct sdap_attr_map netgroup_map[] = {
     SDAP_ATTR_MAP_TERMINATOR
 };
 
+struct sdap_attr_map host_map[] = {
+    { "ldap_host_object_class", "ipHost", SYSDB_HOST_CLASS, NULL },
+    { "ldap_host_name", "cn", SYSDB_NAME, NULL },
+    { "ldap_host_fqdn", "fqdn", SYSDB_FQDN, NULL },
+    { "ldap_host_serverhostname", "serverHostname", SYSDB_SERVERHOSTNAME, NULL },
+    { "ldap_host_member_of", NULL, SYSDB_ORIG_MEMBEROF, NULL },
+    { "ldap_host_ssh_public_key", "sshPublicKey", SYSDB_SSH_PUBKEY, NULL },
+    { "ldap_host_uuid", NULL, SYSDB_UUID, NULL},
+    SDAP_ATTR_MAP_TERMINATOR
+};
+
 struct sdap_attr_map native_sudorule_map[] = {
     { "ldap_sudorule_object_class", "sudoRole", SYSDB_SUDO_CACHE_OC, NULL },
     { "ldap_sudorule_name", "cn", SYSDB_SUDO_CACHE_AT_CN, NULL },
diff --git a/src/providers/ldap/ldap_opts.h b/src/providers/ldap/ldap_opts.h
index ef09a02..3c9a7fc 100644
--- a/src/providers/ldap/ldap_opts.h
+++ b/src/providers/ldap/ldap_opts.h
@@ -48,6 +48,8 @@ extern struct sdap_attr_map gen_ad2008r2_group_map[];
 
 extern struct sdap_attr_map netgroup_map[];
 
+extern struct sdap_attr_map host_map[];
+
 extern struct sdap_attr_map native_sudorule_map[];
 
 extern struct sdap_attr_map service_map[];
diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c
index d562a96..b690660 100644
--- a/src/providers/ldap/sdap.c
+++ b/src/providers/ldap/sdap.c
@@ -1136,6 +1136,9 @@ static errno_t sdap_set_search_base(struct sdap_options *opts,
     case SDAP_NETGROUP_SEARCH_BASE:
         bases = &sdom->netgroup_search_bases;
         break;
+    case SDAP_HOST_SEARCH_BASE:
+        bases = &sdom->host_search_bases;
+        break;
     case SDAP_SUDO_SEARCH_BASE:
         bases = &sdom->sudo_search_bases;
         break;
@@ -1178,6 +1181,7 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse,
             || !sdom->user_search_bases
             || !sdom->group_search_bases
             || !sdom->netgroup_search_bases
+            || !sdom->host_search_bases
             || !sdom->sudo_search_bases
             || !sdom->autofs_search_bases) {
         naming_context = get_naming_context(opts->basic, rootdse);
@@ -1225,6 +1229,14 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse,
         if (ret != EOK) goto done;
     }
 
+    /* Hosts */
+    if (!sdom->host_search_bases) {
+        ret = sdap_set_search_base(opts, sdom,
+                                   SDAP_HOST_SEARCH_BASE,
+                                   naming_context);
+        if (ret != EOK) goto done;
+    }
+
     /* Sudo */
     if (!sdom->sudo_search_bases) {
        ret = sdap_set_search_base(opts, sdom,
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index afdc019..6e79467 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -162,6 +162,7 @@ enum sdap_basic_opt {
     SDAP_GROUP_SEARCH_BASE,
     SDAP_GROUP_SEARCH_SCOPE,
     SDAP_GROUP_SEARCH_FILTER,
+    SDAP_HOST_SEARCH_BASE,
     SDAP_SERVICE_SEARCH_BASE,
     SDAP_SUDO_SEARCH_BASE,
     SDAP_SUDO_FULL_REFRESH_INTERVAL,
@@ -339,6 +340,18 @@ enum sdap_sudorule_attrs {
     SDAP_OPTS_SUDO  /* attrs counter */
 };
 
+enum sdap_host_attrs {
+    SDAP_OC_HOST = 0,
+    SDAP_AT_HOST_NAME,
+    SDAP_AT_HOST_FQDN,
+    SDAP_AT_HOST_SERVERHOSTNAME,
+    SDAP_AT_HOST_MEMBER_OF,
+    SDAP_AT_HOST_SSH_PUBLIC_KEY,
+    SDAP_AT_HOST_UUID,
+
+    SDAP_OPTS_HOST /* attrs counter */
+};
+
 enum sdap_service_attrs {
     SDAP_OC_SERVICE = 0,
     SDAP_AT_SERVICE_NAME,
@@ -406,6 +419,7 @@ struct sdap_domain {
     struct sdap_search_base **user_search_bases;
     struct sdap_search_base **group_search_bases;
     struct sdap_search_base **netgroup_search_bases;
+    struct sdap_search_base **host_search_bases;
     struct sdap_search_base **sudo_search_bases;
     struct sdap_search_base **service_search_bases;
     struct sdap_search_base **autofs_search_bases;
@@ -453,6 +467,7 @@ struct sdap_options {
     size_t user_map_cnt;
     struct sdap_attr_map *group_map;
     struct sdap_attr_map *netgroup_map;
+    struct sdap_attr_map *host_map;
     struct sdap_attr_map *service_map;
 
     /* ID-mapping support */
diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
index 6e5800b..a7a7990 100644
--- a/src/providers/ldap/sdap_async.h
+++ b/src/providers/ldap/sdap_async.h
@@ -123,6 +123,21 @@ int sdap_get_netgroups_recv(struct tevent_req *req,
                             size_t *reply_count,
                             struct sysdb_attrs ***reply);
 
+struct tevent_req *
+sdap_host_info_send(TALLOC_CTX *mem_ctx,
+                    struct tevent_context *ev,
+                    struct sdap_handle *sh,
+                    struct sdap_options *opts,
+                    const char *hostname,
+                    struct sdap_attr_map *host_map,
+                    struct sdap_search_base **search_bases);
+
+errno_t
+sdap_host_info_recv(struct tevent_req *req,
+                    TALLOC_CTX *mem_ctx,
+                    size_t *host_count,
+                    struct sysdb_attrs ***hosts);
+
 struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx,
                                   struct tevent_context *ev,
                                   struct sdap_handle *sh,
diff --git a/src/providers/ldap/sdap_async_hosts.c b/src/providers/ldap/sdap_async_hosts.c
new file mode 100644
index 0000000..0b39e3f
--- /dev/null
+++ b/src/providers/ldap/sdap_async_hosts.c
@@ -0,0 +1,212 @@
+/*
+    SSSD
+
+    Authors:
+        Jan Zeleny <jzel...@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 "providers/ldap/sdap_async_private.h"
+#include "providers/ldap/ldap_common.h"
+
+struct sdap_host_state {
+    struct tevent_context *ev;
+    struct sdap_handle *sh;
+    struct sdap_options *opts;
+    const char **attrs;
+    struct sdap_attr_map *host_map;
+
+    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;
+};
+
+static void
+sdap_host_info_done(struct tevent_req *subreq);
+
+static errno_t
+sdap_host_info_next(struct tevent_req *req,
+                        struct sdap_host_state *state);
+
+/**
+ * hostname == NULL -> look up all hosts / host groups
+ * hostname != NULL -> look up only given host and groups
+ *                     it's member of
+ */
+struct tevent_req *
+sdap_host_info_send(TALLOC_CTX *mem_ctx,
+                   struct tevent_context *ev,
+                   struct sdap_handle *sh,
+                   struct sdap_options *opts,
+                   const char *hostname,
+                   struct sdap_attr_map *host_map,
+                   struct sdap_search_base **search_bases)
+{
+    errno_t ret;
+    struct sdap_host_state *state;
+    struct tevent_req *req;
+
+    req = tevent_req_create(mem_ctx, &state, struct sdap_host_state);
+    if (req == NULL) {
+        return NULL;
+    }
+
+    state->ev = ev;
+    state->sh = sh;
+    state->opts = opts;
+    state->hostname = hostname;
+    state->search_bases = search_bases;
+    state->search_base_iter = 0;
+    state->cur_filter = NULL;
+    state->host_map = host_map;
+
+    ret = build_attrs_from_map(state, host_map, SDAP_OPTS_HOST,
+                               NULL, &state->attrs, NULL);
+    if (ret != EOK) {
+        goto immediate;
+    }
+
+    if (hostname == NULL) {
+        state->host_filter = talloc_asprintf(state, "(objectClass=%s)",
+                                             host_map[SDAP_OC_HOST].name);
+    } else {
+        state->host_filter = talloc_asprintf(state, "(&(objectClass=%s)(%s=%s))",
+                                             host_map[SDAP_OC_HOST].name,
+                                             host_map[SDAP_AT_HOST_FQDN].name,
+                                             hostname);
+    }
+    if (state->host_filter == NULL) {
+        ret = ENOMEM;
+        goto immediate;
+    }
+
+    ret = sdap_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 sdap_host_info_next(struct tevent_req *req,
+                                   struct sdap_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_combine_filters(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, state->host_map,
+                                   SDAP_OPTS_HOST,
+                                   dp_opt_get_int(state->opts->basic,
+                                                  SDAP_ENUM_SEARCH_TIMEOUT),
+                                   true);
+    if (subreq == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Error requesting host info\n");
+        talloc_zfree(state->cur_filter);
+        return EIO;
+    }
+    tevent_req_set_callback(subreq, sdap_host_info_done, req);
+
+    return EAGAIN;
+}
+
+static void
+sdap_host_info_done(struct tevent_req *subreq)
+{
+    errno_t ret;
+    struct tevent_req *req =
+            tevent_req_callback_data(subreq, struct tevent_req);
+    struct sdap_host_state *state =
+            tevent_req_data(req, struct sdap_host_state);
+
+    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 = sdap_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;
+    }
+
+    /* Nothing else to do, just complete the req */
+    tevent_req_done(req);
+}
+
+errno_t sdap_host_info_recv(struct tevent_req *req,
+                           TALLOC_CTX *mem_ctx,
+                           size_t *host_count,
+                           struct sysdb_attrs ***hosts)
+{
+    struct sdap_host_state *state =
+            tevent_req_data(req, struct sdap_host_state);
+
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    *host_count = state->host_count;
+    *hosts = talloc_steal(mem_ctx, state->hosts);
+
+    return EOK;
+}
diff --git a/src/providers/ldap/sdap_hostid.c b/src/providers/ldap/sdap_hostid.c
new file mode 100644
index 0000000..d90a838
--- /dev/null
+++ b/src/providers/ldap/sdap_hostid.c
@@ -0,0 +1,324 @@
+/*
+    Authors:
+        Jan Cholasta <jchol...@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 "util/crypto/sss_crypto.h"
+#include "db/sysdb_ssh.h"
+#include "providers/ldap/ldap_common.h"
+#include "providers/ldap/sdap_async.h"
+#include "providers/ldap/sdap_hostid.h"
+
+struct hosts_get_state {
+    struct tevent_context *ev;
+    struct sdap_id_ctx *id_ctx;
+    struct sdap_id_op *op;
+    struct sss_domain_info *domain;
+    const char *name;
+    const char *alias;
+
+    size_t count;
+    struct sysdb_attrs **hosts;
+    int dp_error;
+};
+
+static errno_t
+hosts_get_retry(struct tevent_req *req);
+static void
+hosts_get_connect_done(struct tevent_req *subreq);
+static void
+hosts_get_done(struct tevent_req *subreq);
+
+struct tevent_req *
+hosts_get_send(TALLOC_CTX *memctx,
+               struct tevent_context *ev,
+               struct sdap_id_ctx *id_ctx,
+               const char *name,
+               const char *alias)
+{
+    struct tevent_req *req;
+    struct hosts_get_state *state;
+    errno_t ret;
+
+    req = tevent_req_create(memctx, &state, struct hosts_get_state);
+    if (!req) return NULL;
+
+    state->ev = ev;
+    state->id_ctx = id_ctx;
+    state->dp_error = DP_ERR_FATAL;
+
+    state->op = sdap_id_op_create(state, id_ctx->conn->conn_cache);
+    if (!state->op) {
+        DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
+        ret = ENOMEM;
+        goto fail;
+    }
+
+    state->domain = id_ctx->be->domain;
+    state->name = name;
+    state->alias = alias;
+
+    ret = hosts_get_retry(req);
+    if (ret != EOK) {
+        goto fail;
+    }
+
+    return req;
+
+fail:
+    tevent_req_error(req, ret);
+    tevent_req_post(req, ev);
+    return req;
+}
+
+static errno_t
+hosts_get_retry(struct tevent_req *req)
+{
+    struct hosts_get_state *state = tevent_req_data(req,
+                                                    struct hosts_get_state);
+    struct tevent_req *subreq;
+    errno_t ret = EOK;
+
+    subreq = sdap_id_op_connect_send(state->op, state, &ret);
+    if (!subreq) {
+        return ret;
+    }
+
+    tevent_req_set_callback(subreq, hosts_get_connect_done, req);
+    return EOK;
+}
+
+static void
+hosts_get_connect_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                      struct tevent_req);
+    struct hosts_get_state *state = tevent_req_data(req,
+                                                    struct hosts_get_state);
+    int dp_error = DP_ERR_FATAL;
+    errno_t ret;
+
+    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;
+    }
+
+    subreq = sdap_host_info_send(state, state->ev,
+                                 sdap_id_op_handle(state->op),
+                                 state->id_ctx->opts, state->name,
+                                 state->id_ctx->opts->host_map,
+                                 state->id_ctx->opts->sdom->host_search_bases);
+    if (!subreq) {
+        tevent_req_error(req, ENOMEM);
+        return;
+    }
+    tevent_req_set_callback(subreq, hosts_get_done, req);
+}
+
+static void
+hosts_get_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req = tevent_req_callback_data(subreq,
+                                                      struct tevent_req);
+    struct hosts_get_state *state = tevent_req_data(req,
+                                                    struct hosts_get_state);
+    int dp_error = DP_ERR_FATAL;
+    errno_t ret;
+    struct sysdb_attrs *attrs;
+    time_t now = time(NULL);
+
+    ret = sdap_host_info_recv(subreq, state,
+                              &state->count, &state->hosts);
+    talloc_zfree(subreq);
+
+    ret = sdap_id_op_done(state->op, ret, &dp_error);
+    if (dp_error == DP_ERR_OK && ret != EOK) {
+        /* retry */
+        ret = hosts_get_retry(req);
+        if (ret != EOK) {
+            goto done;
+        }
+        return;
+    }
+
+    if (ret != EOK && ret != ENOENT) {
+        goto done;
+    }
+
+    if (state->count == 0) {
+        DEBUG(SSSDBG_OP_FAILURE,
+              "No host with name [%s] found.\n", state->name);
+
+        ret = sysdb_delete_ssh_host(state->domain, state->name);
+        if (ret != EOK && ret != ENOENT) {
+            goto done;
+        }
+
+        ret = EINVAL;
+        goto done;
+    }
+
+    if (state->count > 1) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Found more than one host with name [%s].\n", state->name);
+        ret = EINVAL;
+        goto done;
+    }
+
+    attrs = sysdb_new_attrs(state);
+    if (!attrs) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    /* we are interested only in the host keys */
+    ret = sysdb_attrs_copy_values(state->hosts[0], attrs, SYSDB_SSH_PUBKEY);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    ret = sysdb_store_ssh_host(state->domain, state->name, state->alias,
+                               state->domain->ssh_host_timeout, now, attrs);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    dp_error = DP_ERR_OK;
+
+done:
+    state->dp_error = dp_error;
+    if (ret == EOK) {
+        tevent_req_done(req);
+    } else {
+        tevent_req_error(req, ret);
+    }
+}
+
+static errno_t
+hosts_get_recv(struct tevent_req *req,
+               int *dp_error_out)
+{
+    struct hosts_get_state *state = tevent_req_data(req,
+                                                    struct hosts_get_state);
+
+    if (dp_error_out) {
+        *dp_error_out = state->dp_error;
+    }
+
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    return EOK;
+}
+
+struct sdap_hostid_handler_state {
+    struct dp_reply_std reply;
+};
+
+static void sdap_hostid_handler_done(struct tevent_req *subreq);
+
+struct tevent_req *
+sdap_hostid_handler_send(TALLOC_CTX *mem_ctx,
+                         struct sdap_id_ctx *id_ctx,
+                         struct dp_hostid_data *data,
+                         struct dp_req_params *params)
+{
+    struct sdap_hostid_handler_state *state;
+    struct tevent_req *subreq;
+    struct tevent_req *req;
+    errno_t ret;
+
+    req = tevent_req_create(mem_ctx, &state, struct sdap_hostid_handler_state);
+    if (req == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
+        return NULL;
+    }
+
+    subreq = hosts_get_send(state, params->ev, id_ctx,
+                            data->name, data->alias);
+    if (subreq == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to send request\n");
+        ret = ENOMEM;
+        goto immediately;
+    }
+
+    tevent_req_set_callback(subreq, sdap_hostid_handler_done, req);
+
+    return req;
+
+immediately:
+    dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ret, NULL);
+
+    /* 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 sdap_hostid_handler_done(struct tevent_req *subreq)
+{
+    struct sdap_hostid_handler_state *state;
+    struct tevent_req *req;
+    int dp_error;
+    errno_t ret;
+
+    req = tevent_req_callback_data(subreq, struct tevent_req);
+    state = tevent_req_data(req, struct sdap_hostid_handler_state);
+
+    ret = hosts_get_recv(subreq, &dp_error);
+    talloc_zfree(subreq);
+
+    /* TODO For backward compatibility we always return EOK to DP now. */
+    dp_reply_std_set(&state->reply, dp_error, ret, NULL);
+    tevent_req_done(req);
+}
+
+errno_t
+sdap_hostid_handler_recv(TALLOC_CTX *mem_ctx,
+                         struct tevent_req *req,
+                         struct dp_reply_std *data)
+{
+    struct sdap_hostid_handler_state *state = NULL;
+
+    state = tevent_req_data(req, struct sdap_hostid_handler_state);
+
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    *data = state->reply;
+
+    return EOK;
+}
+
+errno_t sdap_hostid_init(TALLOC_CTX *mem_ctx,
+                         struct be_ctx *be_ctx,
+                         struct sdap_id_ctx *id_ctx,
+                         struct dp_method *dp_methods)
+{
+    (void)be_ctx;
+
+    dp_set_method(dp_methods, DPM_HOSTID_HANDLER,
+                  sdap_hostid_handler_send, sdap_hostid_handler_recv, id_ctx,
+                  struct sdap_id_ctx, struct dp_hostid_data, struct dp_reply_std);
+
+    return EOK;
+}
diff --git a/src/providers/ipa/ipa_hostid.h b/src/providers/ldap/sdap_hostid.h
similarity index 55%
rename from src/providers/ipa/ipa_hostid.h
rename to src/providers/ldap/sdap_hostid.h
index 2611e45..6968cbd 100644
--- a/src/providers/ipa/ipa_hostid.h
+++ b/src/providers/ldap/sdap_hostid.h
@@ -18,25 +18,24 @@
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#ifndef _IPA_HOSTID_H_
-#define _IPA_HOSTID_H_
+#ifndef _SDAP_HOSTID_H_
+#define _SDAP_HOSTID_H_
 
-struct ipa_hostid_ctx {
-    struct sdap_id_ctx *sdap_id_ctx;
-    struct ipa_options *ipa_opts;
-
-    struct sdap_search_base **host_search_bases;
-};
+errno_t sdap_hostid_init(TALLOC_CTX *mem_ctx,
+                         struct be_ctx *be_ctx,
+                         struct sdap_id_ctx *id_ctx,
+                         struct dp_method *dp_methods);
 
 struct tevent_req *
-ipa_hostid_handler_send(TALLOC_CTX *mem_ctx,
-                       struct ipa_hostid_ctx *hostid_ctx,
-                       struct dp_hostid_data *data,
-                       struct dp_req_params *params);
+sdap_hostid_handler_send(TALLOC_CTX *mem_ctx,
+                         struct sdap_id_ctx *id_ctx,
+                         struct dp_hostid_data *data,
+                         struct dp_req_params *params);
 
 errno_t
-ipa_hostid_handler_recv(TALLOC_CTX *mem_ctx,
-                       struct tevent_req *req,
-                       struct dp_reply_std *data);
+sdap_hostid_handler_recv(TALLOC_CTX *mem_ctx,
+                         struct tevent_req *req,
+                         struct dp_reply_std *data);
+
+#endif /* _SDAP_HOSTID_H_ */
 
-#endif /* _IPA_HOSTID_H_ */
diff --git a/src/tests/ipa_ldap_opt-tests.c b/src/tests/ipa_ldap_opt-tests.c
index 30e09f7..8c7c81f 100644
--- a/src/tests/ipa_ldap_opt-tests.c
+++ b/src/tests/ipa_ldap_opt-tests.c
@@ -230,7 +230,7 @@ START_TEST(test_sdap_opt_sentinel)
     fail_unless_sdap_opt_is_terminator(&ad_netgroup_map[SDAP_OPTS_NETGROUP]);
     fail_unless_sdap_opt_is_terminator(&ipa_netgroup_map[IPA_OPTS_NETGROUP]);
 
-    fail_unless_sdap_opt_is_terminator(&ipa_host_map[IPA_OPTS_HOST]);
+    fail_unless_sdap_opt_is_terminator(&ipa_host_map[SDAP_OPTS_HOST]);
     fail_unless_sdap_opt_is_terminator(&ipa_hostgroup_map[IPA_OPTS_HOSTGROUP]);
     fail_unless_sdap_opt_is_terminator(&ipa_selinux_user_map[IPA_OPTS_SELINUX_USERMAP]);
     fail_unless_sdap_opt_is_terminator(&ipa_view_map[IPA_OPTS_VIEW]);
_______________________________________________
sssd-devel mailing list -- sssd-devel@lists.fedorahosted.org
To unsubscribe send an email to sssd-devel-le...@lists.fedorahosted.org

Reply via email to