From 7ceb5c969ad05018189ec3851c93781d78b33f07 Mon Sep 17 00:00:00 2001
From: Jan Zeleny <jzeleny@redhat.com>
Date: Fri, 4 Nov 2011 13:16:47 -0400
Subject: [PATCH] Add ipa_hbac_support_srchost option to IPA provider

don't fetch all host groups if this option is false
https://fedorahosted.org/sssd/ticket/1078
---
 src/config/SSSDConfig.py                |    1 +
 src/config/etc/sssd.api.d/sssd-ipa.conf |    1 +
 src/man/sssd-ipa.5.xml                  |   12 ++
 src/providers/ipa/ipa_access.c          |    4 +
 src/providers/ipa/ipa_common.c          |    3 +-
 src/providers/ipa/ipa_common.h          |    1 +
 src/providers/ipa/ipa_hbac_common.c     |    3 +
 src/providers/ipa/ipa_hbac_hosts.c      |  178 +++++++++++++++++++++++++++----
 src/providers/ipa/ipa_hbac_private.h    |    3 +
 9 files changed, 185 insertions(+), 21 deletions(-)

diff --git a/src/config/SSSDConfig.py b/src/config/SSSDConfig.py
index 87b1d63413cd914401aeccdc6ad2eec12af92a66..b6d1b6f070afd73dd0a32b1c58c6e312255c82fa 100644
--- a/src/config/SSSDConfig.py
+++ b/src/config/SSSDConfig.py
@@ -102,6 +102,7 @@ option_strings = {
     'ipa_hbac_search_base' : _("Search base for HBAC related objects"),
     'ipa_hbac_refresh' : _("The amount of time between lookups of the HBAC rules against the IPA server"),
     'ipa_hbac_treat_deny_as' : _("If DENY rules are present, either DENY_ALL or IGNORE"),
+    'ipa_hbac_support_srchost' : _("If set to false, host argument given by PAM will be ignored"),
 
     # [provider/krb5]
     'krb5_kdcip' : _('Kerberos server address'),
diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf
index 9ea45285ec93c4afe0ea2210c5a27a68de894b3f..697db819cbb165f1c4febeb2c417607444221bbe 100644
--- a/src/config/etc/sssd.api.d/sssd-ipa.conf
+++ b/src/config/etc/sssd.api.d/sssd-ipa.conf
@@ -106,6 +106,7 @@ krb5_fast_principal = str, None, false
 [provider/ipa/access]
 ipa_hbac_refresh = int, None, false
 ipa_hbac_treat_deny_as = str, None, false
+ipa_hbac_support_srchost = bool, None, false
 
 [provider/ipa/chpass]
 
diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml
index 2c1a0ed8c37b4429b1929637807d3cbedcca1d68..105f5c7283f70e3cb6fae978f19d966b02460d75 100644
--- a/src/man/sssd-ipa.5.xml
+++ b/src/man/sssd-ipa.5.xml
@@ -234,6 +234,18 @@
                         </para>
                     </listitem>
                 </varlistentry>
+                <varlistentry>
+                    <term>ipa_hbac_support_srchost (boolean)</term>
+                    <listitem>
+                        <para>
+                            If this is set to false, then srchost as given
+                            to SSSD by PAM will be ignored.
+                        </para>
+                        <para>
+                            Default: false
+                        </para>
+                    </listitem>
+                </varlistentry>
 
             </variablelist>
         </para>
diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c
index 10f1cb7e6e2685b9dc6ac7f05ae53a37ebce345e..657e1169b6dc9539fbd28f9bae48931f8717875a 100644
--- a/src/providers/ipa/ipa_access.c
+++ b/src/providers/ipa/ipa_access.c
@@ -299,6 +299,10 @@ static int hbac_get_host_info_step(struct hbac_ctx *hbac_ctx)
                                     hbac_ctx_be(hbac_ctx)->domain,
                                     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->hbac_search_base);
     if (req == NULL) {
         DEBUG(1, ("Could not get host info\n"));
diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
index 8f9d5d77955cb7b01bfac69fc4ba00b136f866f2..e361b276a769160d9d0ff50a47be819a079f641d 100644
--- a/src/providers/ipa/ipa_common.c
+++ b/src/providers/ipa/ipa_common.c
@@ -39,7 +39,8 @@ struct dp_option ipa_basic_opts[] = {
     { "ipa_hbac_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING},
     { "krb5_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING},
     { "ipa_hbac_refresh", DP_OPT_NUMBER, { .number = 5 }, NULL_NUMBER },
-    { "ipa_hbac_treat_deny_as", DP_OPT_STRING, { "DENY_ALL" }, NULL_STRING }
+    { "ipa_hbac_treat_deny_as", DP_OPT_STRING, { "DENY_ALL" }, NULL_STRING },
+    { "ipa_hbac_support_srchost", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }
 };
 
 struct dp_option ipa_def_ldap_opts[] = {
diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h
index 40c5e53205285d761a43f6f0a77764006a5d79ca..65749216ca02ab761d057a10195dda28dbedd43a 100644
--- a/src/providers/ipa/ipa_common.h
+++ b/src/providers/ipa/ipa_common.h
@@ -52,6 +52,7 @@ enum ipa_basic_opt {
     IPA_KRB5_REALM,
     IPA_HBAC_REFRESH,
     IPA_HBAC_DENY_METHOD,
+    IPA_HBAC_SUPPORT_SRCHOST,
 
     IPA_OPTS_BASIC /* opts counter */
 };
diff --git a/src/providers/ipa/ipa_hbac_common.c b/src/providers/ipa/ipa_hbac_common.c
index 8815dae182e9352b321546158ebe535e443f2ab6..dcf6e659adbe30f39efbabd63153fbe9f763fe5b 100644
--- a/src/providers/ipa/ipa_hbac_common.c
+++ b/src/providers/ipa/ipa_hbac_common.c
@@ -336,11 +336,14 @@ hbac_attrs_to_rule(TALLOC_CTX *mem_ctx,
     }
 
     /* Get the source hosts */
+
     ret = hbac_shost_attrs_to_rule(new_rule,
                                    hbac_ctx_sysdb(hbac_ctx),
                                    hbac_ctx_be(hbac_ctx)->domain,
                                    new_rule->name,
                                    hbac_ctx->rules[idx],
+                                   dp_opt_get_bool(hbac_ctx->ipa_options,
+                                                   IPA_HBAC_SUPPORT_SRCHOST),
                                    &new_rule->srchosts);
     if (ret != EOK) {
         DEBUG(1, ("Could not parse source hosts for rule [%s]\n",
diff --git a/src/providers/ipa/ipa_hbac_hosts.c b/src/providers/ipa/ipa_hbac_hosts.c
index 42a3f5c1b8946341abff1b5a5cafa8a07abfba3c..b394379787d1dc6670cf1896503be3210ce99398 100644
--- a/src/providers/ipa/ipa_hbac_hosts.c
+++ b/src/providers/ipa/ipa_hbac_hosts.c
@@ -34,18 +34,33 @@ struct ipa_hbac_host_state {
     const char *search_base;
     const char **attrs;
 
+    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_deref_info_done(struct tevent_req *subreq);
+static void
 ipa_hbac_hostgroup_info_done(struct tevent_req *subreq);
 
 struct tevent_req *
@@ -55,6 +70,8 @@ ipa_hbac_host_info_send(TALLOC_CTX *mem_ctx,
                         struct sss_domain_info *dom,
                         struct sdap_handle *sh,
                         struct sdap_options *opts,
+                        bool support_srchost,
+                        const char *hostname,
                         const char *search_base)
 {
     errno_t ret;
@@ -73,9 +90,20 @@ ipa_hbac_host_info_send(TALLOC_CTX *mem_ctx,
     state->dom = dom;
     state->sh = sh;
     state->opts = opts;
+    state->support_srchost = support_srchost;
+    state->hostname = hostname;
     state->search_base = search_base;
 
-    host_filter = talloc_asprintf(state, "(objectClass=%s)", IPA_HOST);
+    if (support_srchost) {
+        host_filter = talloc_asprintf(state, "(objectClass=%s)", IPA_HOST);
+    } else {
+        if (hostname == NULL) {
+            ret = EINVAL;
+            goto immediate;
+        }
+        host_filter = talloc_asprintf(state, "(&(objectClass=%s)(%s=%s))",
+                                      IPA_HOST, IPA_HOST_FQDN, hostname);
+    }
     if (host_filter == NULL) {
         ret = ENOMEM;
         goto immediate;
@@ -129,6 +157,8 @@ ipa_hbac_host_info_done(struct tevent_req *subreq)
     struct ipa_hbac_host_state *state =
             tevent_req_data(req, struct ipa_hbac_host_state);
     char *hostgroup_filter;
+    const char *host_dn;
+    int i;
 
     ret = sdap_get_generic_recv(subreq, state,
                                 &state->host_count,
@@ -153,25 +183,66 @@ ipa_hbac_host_info_done(struct tevent_req *subreq)
         return;
     }
 
-    hostgroup_filter = talloc_asprintf(state, "(objectClass=%s)",
-                                              IPA_HOSTGROUP);
-    if (hostgroup_filter == NULL) {
-        tevent_req_error(req, ENOMEM);
-        return;
-    }
-
     /* Look up host groups */
-    subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
-                                   state->search_base, LDAP_SCOPE_SUB,
-                                   hostgroup_filter, state->attrs, NULL, 0,
-                                   dp_opt_get_int(state->opts->basic,
-                                                  SDAP_ENUM_SEARCH_TIMEOUT));
-    if (subreq == NULL) {
-        DEBUG(1, ("Error requesting host info\n"));
-        tevent_req_error(req, EIO);
-        return;
+    if (state->support_srchost) {
+        hostgroup_filter = talloc_asprintf(state, "(objectClass=%s)",
+                                                  IPA_HOSTGROUP);
+        if (hostgroup_filter == NULL) {
+            tevent_req_error(req, ENOMEM);
+            return;
+        }
+
+        subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
+                                       state->search_base, LDAP_SCOPE_SUB,
+                                       hostgroup_filter, state->attrs, NULL, 0,
+                                       dp_opt_get_int(state->opts->basic,
+                                                      SDAP_ENUM_SEARCH_TIMEOUT));
+        if (subreq == NULL) {
+            DEBUG(1, ("Error requesting host info\n"));
+            tevent_req_error(req, EIO);
+            return;
+        }
+        tevent_req_set_callback(subreq, ipa_hbac_hostgroup_info_done, req);
+    } 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;
+        }
+
+        /* 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;
+            }
+        }
+
+        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(1, ("Error requesting host info\n"));
+            tevent_req_error(req, EIO);
+            return;
+        }
+        tevent_req_set_callback(subreq, ipa_hbac_hostgroup_deref_info_done, req);
     }
-    tevent_req_set_callback(subreq, ipa_hbac_hostgroup_info_done, req);
 }
 
 static void
@@ -214,6 +285,56 @@ done:
     }
 }
 
+static void
+ipa_hbac_hostgroup_deref_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);
+
+    struct sdap_deref_attrs **deref_result;
+    const char *hostgroup_name;
+    int i;
+
+    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;
+        }
+
+        for (i = 0; i < state->hostgroup_count; i++) {
+            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[i] = talloc_steal(state->hostgroups,
+                                                deref_result[i]->attrs);
+        }
+    }
+
+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,
@@ -460,16 +581,33 @@ hbac_shost_attrs_to_rule(TALLOC_CTX *mem_ctx,
                          struct sss_domain_info *domain,
                          const char *rule_name,
                          struct sysdb_attrs *rule_attrs,
+                         bool support_srchost,
                          struct hbac_rule_element **source_hosts)
 {
     errno_t ret;
     size_t host_count;
-    TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+    TALLOC_CTX *tmp_ctx;
     size_t idx;
     struct ldb_message_element *el;
     struct hbac_rule_element *shosts;
 
-    DEBUG(7, ("Processing source hosts for rule [%s]\n", rule_name));
+    tmp_ctx = talloc_new(mem_ctx);
+    if (tmp_ctx == NULL) return ENOMEM;
+
+    DEBUG(SSSDBG_TRACE_FUNC, ("Processing source hosts for rule [%s]\n", rule_name));
+
+    if (!support_srchost) {
+        DEBUG(SSSDBG_TRACE_INTERNAL, ("Source hosts disabled, setting ALL\n"));
+        shosts = talloc_zero(tmp_ctx, struct hbac_rule_element);
+        if (shosts == NULL) {
+            ret = ENOMEM;
+            goto done;
+        }
+
+        shosts->category = HBAC_CATEGORY_ALL;
+        ret = EOK;
+        goto done;
+    }
 
     ret = hbac_host_attrs_to_rule(tmp_ctx, sysdb, domain,
                                   rule_name, rule_attrs,
diff --git a/src/providers/ipa/ipa_hbac_private.h b/src/providers/ipa/ipa_hbac_private.h
index 32b5d70ce8f648378cfbcb3edb36b958cf17f60f..65488a2833557be1e710978687ffe4e6458ccc41 100644
--- a/src/providers/ipa/ipa_hbac_private.h
+++ b/src/providers/ipa/ipa_hbac_private.h
@@ -106,6 +106,8 @@ ipa_hbac_host_info_send(TALLOC_CTX *mem_ctx,
                         struct sss_domain_info *dom,
                         struct sdap_handle *sh,
                         struct sdap_options *opts,
+                        bool support_srchost,
+                        const char *hostname,
                         const char *search_base);
 
 errno_t
@@ -130,6 +132,7 @@ hbac_shost_attrs_to_rule(TALLOC_CTX *mem_ctx,
                          struct sss_domain_info *domain,
                          const char *rule_name,
                          struct sysdb_attrs *rule_attrs,
+                         bool support_srchost,
                          struct hbac_rule_element **source_hosts);
 errno_t
 get_ipa_hostgroupname(TALLOC_CTX *mem_ctx,
-- 
1.7.6.4

