URL: https://github.com/SSSD/sssd/pull/424
Author: jhrozek
 Title: #424: TOOLS: Add a new sssctl command access-report
Action: synchronized

To pull the PR as Git branch:
git remote add ghsssd https://github.com/SSSD/sssd
git fetch ghsssd pull/424/head:pr424
git checkout pr424
From 4ac3e7178f3fde84fedf498cc792e76382e5035d Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <[email protected]>
Date: Mon, 23 Oct 2017 18:08:12 +0200
Subject: [PATCH 1/6] TOOLS: Add a new sssctl command access-report

---
 Makefile.am                             |   1 +
 src/tools/sssctl/sssctl.c               |   1 +
 src/tools/sssctl/sssctl.h               |   5 +
 src/tools/sssctl/sssctl_access_report.c | 435 ++++++++++++++++++++++++++++++++
 4 files changed, 442 insertions(+)
 create mode 100644 src/tools/sssctl/sssctl_access_report.c

diff --git a/Makefile.am b/Makefile.am
index 286ba47e3..2e420e4cb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1751,6 +1751,7 @@ sssctl_SOURCES = \
     src/tools/sssctl/sssctl_sifp.c \
     src/tools/sssctl/sssctl_config.c \
     src/tools/sssctl/sssctl_user_checks.c \
+    src/tools/sssctl/sssctl_access_report.c \
     $(SSSD_TOOLS_OBJ) \
     $(NULL)
 sssctl_LDADD = \
diff --git a/src/tools/sssctl/sssctl.c b/src/tools/sssctl/sssctl.c
index d9bc897c1..afaa84bc0 100644
--- a/src/tools/sssctl/sssctl.c
+++ b/src/tools/sssctl/sssctl.c
@@ -264,6 +264,7 @@ int main(int argc, const char **argv)
         SSS_TOOL_COMMAND("domain-list", "List available domains", 0, sssctl_domain_list),
         SSS_TOOL_COMMAND("domain-status", "Print information about domain", 0, sssctl_domain_status),
         SSS_TOOL_COMMAND("user-checks", "Print information about a user and check authentication", 0, sssctl_user_checks),
+        SSS_TOOL_COMMAND("access-report", "Generate access report for a domain", 0, sssctl_access_report),
         SSS_TOOL_DELIMITER("Information about cached content:"),
         SSS_TOOL_COMMAND("user-show", "Information about cached user", 0, sssctl_user_show),
         SSS_TOOL_COMMAND("group-show", "Information about cached group", 0, sssctl_group_show),
diff --git a/src/tools/sssctl/sssctl.h b/src/tools/sssctl/sssctl.h
index 22ca5d41e..70fc19eff 100644
--- a/src/tools/sssctl/sssctl.h
+++ b/src/tools/sssctl/sssctl.h
@@ -133,4 +133,9 @@ errno_t sssctl_config_check(struct sss_cmdline *cmdline,
 errno_t sssctl_user_checks(struct sss_cmdline *cmdline,
                            struct sss_tool_ctx *tool_ctx,
                            void *pvt);
+
+errno_t sssctl_access_report(struct sss_cmdline *cmdline,
+                             struct sss_tool_ctx *tool_ctx,
+                             void *pvt);
+
 #endif /* _SSSCTL_H_ */
diff --git a/src/tools/sssctl/sssctl_access_report.c b/src/tools/sssctl/sssctl_access_report.c
new file mode 100644
index 000000000..111723298
--- /dev/null
+++ b/src/tools/sssctl/sssctl_access_report.c
@@ -0,0 +1,435 @@
+/*
+    Copyright (C) 2017 Red Hat
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <security/pam_appl.h>
+
+#include "util/util.h"
+#include "tools/common/sss_tools.h"
+#include "tools/sssctl/sssctl.h"
+
+/*
+ * We're searching the cache directly..
+ */
+#include "providers/ipa/ipa_hbac_private.h"
+#include "providers/ipa/ipa_rules_common.h"
+
+#ifdef HAVE_SECURITY_PAM_MISC_H
+# include <security/pam_misc.h>
+#elif defined(HAVE_SECURITY_OPENPAM_H)
+# include <security/openpam.h>
+#endif
+
+#ifdef HAVE_SECURITY_PAM_MISC_H
+static struct pam_conv conv = {
+    misc_conv,
+    NULL
+};
+#elif defined(HAVE_SECURITY_OPENPAM_H)
+static struct pam_conv conv = {
+    openpam_ttyconv,
+    NULL
+};
+#else
+# error "Missing text based pam conversation function"
+#endif
+
+#ifndef DEFAULT_SERVICE
+#define DEFAULT_SERVICE "system-auth"
+#endif /* DEFAULT_SERVICE */
+
+#ifndef DEFAULT_USER
+#define DEFAULT_USER "admin"
+#endif /* DEFAULT_USER */
+
+typedef errno_t (*sssctl_dom_access_reporter_fn)(struct sss_tool_ctx *tool_ctx,
+                                                 const char *user,
+                                                 const char *service,
+                                                 struct sss_domain_info *domain);
+
+static errno_t run_pam_acct(struct sss_tool_ctx *tool_ctx,
+                            const char *user,
+                            const char *service,
+                            struct sss_domain_info *domain)
+{
+    errno_t ret;
+    pam_handle_t *pamh;
+
+    ret = pam_start(service, user, &conv, &pamh);
+    if (ret != PAM_SUCCESS) {
+        ERROR("pam_start failed: %s\n", pam_strerror(pamh, ret));
+        return EIO;
+    }
+
+    ret = pam_acct_mgmt(pamh, 0);
+    pam_end(pamh, ret);
+    return ret;
+}
+
+static errno_t get_rdn_value(TALLOC_CTX *mem_ctx,
+                             struct sss_domain_info *dom,
+                             const char *dn_attr,
+                             const char **_rdn_value)
+{
+    errno_t ret;
+    TALLOC_CTX *tmp_ctx;
+    struct ldb_dn *dn = NULL;
+    const struct ldb_val *rdn_val;
+    const char *rdn_str;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        return ENOMEM;
+    }
+
+    dn = ldb_dn_new(tmp_ctx, sysdb_ctx_get_ldb(dom->sysdb), dn_attr);
+    if (dn == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    rdn_val = ldb_dn_get_rdn_val(dn);
+    if (rdn_val == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "No RDN value?\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
+    rdn_str = talloc_strndup(tmp_ctx,
+                               (const char *)rdn_val->data,
+                               rdn_val->length);
+    if (rdn_str == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = EOK;
+    *_rdn_value = talloc_steal(mem_ctx, rdn_str);
+done:
+    talloc_zfree(tmp_ctx);
+    return ret;
+}
+
+static errno_t is_member_group(struct sss_domain_info *dom,
+                               const char *dn_attr,
+                               const char *group_rdn,
+                               bool *_is_group)
+{
+    const char *comp_name;
+    const struct ldb_val *comp_val;
+    TALLOC_CTX *tmp_ctx;
+    bool is_group = false;
+    errno_t ret;
+    struct ldb_dn *dn = NULL;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        return ENOMEM;
+    }
+
+    dn = ldb_dn_new(tmp_ctx, sysdb_ctx_get_ldb(dom->sysdb), dn_attr);
+    if (dn == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    comp_name = ldb_dn_get_component_name(dn, 1);
+    comp_val = ldb_dn_get_component_val(dn, 1);
+    if (strcasecmp("cn", comp_name) == 0
+            && strncasecmp(group_rdn,
+                           (const char *) comp_val->data,
+                           comp_val->length) == 0) {
+        is_group = true;
+    }
+
+    ret = EOK;
+done:
+    *_is_group = is_group;
+    talloc_zfree(tmp_ctx);
+    return ret;
+}
+
+static void print_category(struct sss_domain_info *domain,
+                           struct ldb_message *rule_msg,
+                           const char *category_attr_name,
+                           const char *category_label)
+{
+    struct ldb_message_element *category_attr;
+
+    category_attr = ldb_msg_find_element(rule_msg, category_attr_name);
+    if (category_attr == NULL) {
+        DEBUG(SSSDBG_MINOR_FAILURE, "Cannot find %s\n", category_attr_name);
+        return;
+    }
+
+    if (category_attr->num_values > 0) {
+        PRINT("\t%s: ", category_label);
+        for (unsigned i = 0; i < category_attr->num_values; i++) {
+            PRINT("%s%s",
+                  i > 0 ? ", " : "",
+                  (const char *) category_attr->values[i].data);
+        }
+        PRINT("\n");
+    }
+}
+
+static void print_member_attr(struct sss_domain_info *domain,
+                              struct ldb_message *rule_msg,
+                              const char *member_attr_name,
+                              const char *group_rdn,
+                              const char *object_label,
+                              const char *group_label)
+{
+    errno_t ret;
+    TALLOC_CTX *tmp_ctx = NULL;
+    const char **member_names = NULL;
+    size_t name_count = 0;
+    const char **member_group_names = NULL;
+    size_t group_count = 0;
+    struct ldb_message_element *member_attr = NULL;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        return;
+    }
+
+    member_attr = ldb_msg_find_element(rule_msg, member_attr_name);
+    if (member_attr == NULL) {
+        DEBUG(SSSDBG_MINOR_FAILURE, "Cannot find %s\n", member_attr_name);
+        goto done;
+    }
+
+    member_names = talloc_zero_array(tmp_ctx,
+                                      const char *,
+                                      member_attr->num_values + 1);
+    member_group_names = talloc_zero_array(tmp_ctx,
+                                           const char *,
+                                           member_attr->num_values + 1);
+    if (member_names == NULL || member_group_names == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "OOM?\n");
+        goto done;
+    }
+
+    for (size_t i = 0; i < member_attr->num_values; i++) {
+        bool is_group;
+        const char *rdn_string;
+        const char *dn_attr;
+
+        dn_attr = (const char *) member_attr->values[i].data;
+
+        ret = is_member_group(domain, dn_attr, group_rdn, &is_group);
+        if (ret != EOK) {
+            continue;
+        }
+
+        ret = get_rdn_value(tmp_ctx, domain, dn_attr, &rdn_string);
+        if (ret != EOK) {
+            continue;
+        }
+
+        if (is_group == false) {
+            member_names[name_count] = talloc_steal(member_names,
+                                                    rdn_string);
+            if (member_names[name_count] == NULL) {
+                goto done;
+            }
+            name_count++;
+        } else {
+            member_group_names[group_count] = talloc_strdup(member_group_names,
+                                                            rdn_string);
+            if (member_group_names[group_count] == NULL) {
+                goto done;
+            }
+            group_count++;
+        }
+    }
+
+    if (member_names[0] != NULL) {
+        PRINT("\t%s: ", object_label);
+        for (int i = 0; member_names[i]; i++) {
+            PRINT("%s%s", i > 0 ? ", " : "", member_names[i]);
+        }
+        PRINT("\n");
+    }
+
+    if (member_group_names[0] != NULL) {
+        PRINT("\t%s: ", group_label);
+        for (int i = 0; member_group_names[i]; i++) {
+            PRINT("%s%s", i > 0 ? ", " : "", member_group_names[i]);
+        }
+        PRINT("\n");
+    }
+
+done:
+    talloc_free(tmp_ctx);
+}
+
+static void print_ipa_hbac_rule(struct sss_domain_info *domain,
+                                struct ldb_message *rule_msg)
+{
+    struct ldb_message_element *el;
+
+    el = ldb_msg_find_element(rule_msg, IPA_CN);
+    if (el == NULL || el->num_values < 1) {
+        DEBUG(SSSDBG_MINOR_FAILURE, "A rule with no name\n");
+        return;
+    }
+
+    PRINT("Rule name: %1$s\n", el->values[0].data);
+
+    print_member_attr(domain,
+                      rule_msg,
+                      IPA_MEMBER_USER,
+                      "groups",
+                      _("Member users"),
+                      _("Member groups"));
+    print_category(domain,
+                   rule_msg,
+                   IPA_USER_CATEGORY,
+                   _("User category"));
+
+    print_member_attr(domain,
+                      rule_msg,
+                      IPA_MEMBER_SERVICE,
+                      "hbacservicegroups",
+                      _("Member services"),
+                      _("Member service groups"));
+    print_category(domain,
+                   rule_msg,
+                   IPA_SERVICE_CATEGORY,
+                   _("Service category"));
+
+    PRINT("\n");
+}
+
+static errno_t sssctl_ipa_access_report(struct sss_tool_ctx *tool_ctx,
+                                        const char *user,
+                                        const char *service,
+                                        struct sss_domain_info *domain)
+{
+    TALLOC_CTX *tmp_ctx = NULL;
+    const char *filter = NULL;
+    errno_t ret;
+    const char *attrs[] = {
+        OBJECTCLASS,
+        IPA_CN,
+        IPA_MEMBER_USER,
+        IPA_USER_CATEGORY,
+        IPA_MEMBER_SERVICE,
+        IPA_SERVICE_CATEGORY,
+        IPA_MEMBER_HOST,
+        IPA_HOST_CATEGORY,
+        NULL,
+    };
+    size_t rule_count;
+    struct ldb_message **msgs = NULL;
+
+    /* Run the pam account phase to make sure the rules are fetched by SSSD */
+    ret = run_pam_acct(tool_ctx, user, service, domain);
+    if (ret != PAM_SUCCESS && ret != PAM_PERM_DENIED) {
+        ERROR("Cannot run the PAM account phase, reporting stale rules\n");
+        /* Non-fatal */
+    }
+
+    tmp_ctx = talloc_new(tool_ctx);
+    if (tmp_ctx == NULL) {
+        return ENOMEM;
+    }
+
+    filter = talloc_asprintf(tmp_ctx, "(objectClass=%s)", IPA_HBAC_RULE);
+    if (filter == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = sysdb_search_custom(tmp_ctx, domain, filter,
+                              HBAC_RULES_SUBDIR, attrs,
+                              &rule_count, &msgs);
+    if (ret != EOK && ret != ENOENT) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Error looking up HBAC rules\n");
+        goto done;
+    }
+
+    if (ret == ENOENT) {
+        PRINT("No cached rules. All users will be denied access\n");
+        ret = EOK;
+        goto done;
+    }
+
+    PRINT("%1$zu rules cached\n\n", rule_count);
+
+    for (size_t i = 0; i < rule_count; i++) {
+        print_ipa_hbac_rule(domain, msgs[i]);
+    }
+
+    ret = EOK;
+done:
+    talloc_zfree(tmp_ctx);
+    return ret;
+}
+
+sssctl_dom_access_reporter_fn get_report_fn(const char *provider)
+{
+    if (strcmp(provider, "ipa") == 0) {
+        return sssctl_ipa_access_report;
+    }
+
+    return NULL;
+}
+
+errno_t sssctl_access_report(struct sss_cmdline *cmdline,
+                             struct sss_tool_ctx *tool_ctx,
+                             void *pvt)
+{
+    errno_t ret;
+    const char *domname = NULL;
+    sssctl_dom_access_reporter_fn reporter;
+    struct sss_domain_info *dom;
+    const char *user = DEFAULT_USER;
+    const char *service = DEFAULT_SERVICE;
+
+    /* Parse command line. */
+    struct poptOption options[] = {
+        { "user", 'u', POPT_ARG_STRING, &user, 0,
+          _("PAM user, default: " DEFAULT_USER), NULL },
+        { "service", 's', POPT_ARG_STRING, &service, 0,
+          _("PAM service, default: " DEFAULT_SERVICE), NULL },
+        POPT_TABLEEND
+    };
+
+    ret = sss_tool_popt_ex(cmdline, options, SSS_TOOL_OPT_OPTIONAL,
+                           NULL, NULL, "DOMAIN", _("Specify domain name."),
+                           &domname, NULL);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n");
+        return ret;
+    }
+
+    dom = find_domain_by_name(tool_ctx->domains, domname, true);
+    if (dom == NULL) {
+        ERROR("Cannot find domain %1$s\n", domname);
+        return ERR_DOMAIN_NOT_FOUND;
+    }
+
+    reporter = get_report_fn(dom->provider);
+    if (reporter == NULL) {
+        ERROR("Access report not implemented for domains of type %1$s\n",
+              dom->provider);
+        return ret;
+    }
+
+    return reporter(tool_ctx, user, service, dom);
+}

From 42daffa0d6daf083a5d61661704fbd1d9c8a70d8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <[email protected]>
Date: Thu, 2 Nov 2017 14:58:05 +0100
Subject: [PATCH 2/6] dp: use void * to express empty output argument list

Since we cannot use plain void type is function definition.
---
 src/providers/data_provider/dp_private.h       | 2 +-
 src/providers/data_provider/dp_request_reply.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/providers/data_provider/dp_private.h b/src/providers/data_provider/dp_private.h
index 2e71a373f..028070f7f 100644
--- a/src/providers/data_provider/dp_private.h
+++ b/src/providers/data_provider/dp_private.h
@@ -136,7 +136,7 @@ typedef void (*dp_req_reply_fn)(const char *req_name,
 
 void dp_req_reply_default(const char *req_name,
                           struct sbus_request *sbus_req,
-                          void *data);
+                          void **data);
 
 /* Data provider request table. */
 
diff --git a/src/providers/data_provider/dp_request_reply.c b/src/providers/data_provider/dp_request_reply.c
index 27d9654ba..34440fda7 100644
--- a/src/providers/data_provider/dp_request_reply.c
+++ b/src/providers/data_provider/dp_request_reply.c
@@ -31,7 +31,7 @@
 
 void dp_req_reply_default(const char *req_name,
                           struct sbus_request *sbus_req,
-                          void *data)
+                          void **data)
 {
     DP_REQ_DEBUG(SSSDBG_TRACE_FUNC, req_name, "Replying with empty message");
 

From 307209a899fcfa9b3000eeeff8904d915e9f53a2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <[email protected]>
Date: Thu, 2 Nov 2017 14:58:38 +0100
Subject: [PATCH 3/6] dp: add method to refresh access control rules

---
 src/providers/data_provider/dp.h                 |  2 ++
 src/providers/data_provider/dp_iface.c           |  6 ++++++
 src/providers/data_provider/dp_iface.h           |  4 ++++
 src/providers/data_provider/dp_iface.xml         |  6 ++++++
 src/providers/data_provider/dp_iface_generated.c | 27 ++++++++++++++++++++++++
 src/providers/data_provider/dp_iface_generated.h | 16 ++++++++++++++
 src/providers/data_provider/dp_target_auth.c     | 14 ++++++++++++
 7 files changed, 75 insertions(+)

diff --git a/src/providers/data_provider/dp.h b/src/providers/data_provider/dp.h
index 9cdbe5b3a..aa5b78115 100644
--- a/src/providers/data_provider/dp.h
+++ b/src/providers/data_provider/dp.h
@@ -83,6 +83,8 @@ enum dp_methods {
     DPM_DOMAINS_HANDLER,
     DPM_SESSION_HANDLER,
 
+    DPM_REFRESH_ACCESS_RULES,
+
     DP_METHOD_SENTINEL
 };
 
diff --git a/src/providers/data_provider/dp_iface.c b/src/providers/data_provider/dp_iface.c
index 4b2b0ddca..28d70e686 100644
--- a/src/providers/data_provider/dp_iface.c
+++ b/src/providers/data_provider/dp_iface.c
@@ -48,10 +48,16 @@ struct iface_dp_failover iface_dp_failover = {
     .ListServers = dp_failover_list_servers
 };
 
+struct iface_dp_access_control iface_dp_access_control = {
+    { &iface_dp_access_control_meta, 0 },
+    .RefreshRules = dp_access_control_refresh_rules_handler
+};
+
 static struct sbus_iface_map dp_map[] = {
     { DP_PATH, &iface_dp.vtable },
     { DP_PATH, &iface_dp_backend.vtable },
     { DP_PATH, &iface_dp_failover.vtable },
+    { DP_PATH, &iface_dp_access_control.vtable },
     { NULL, NULL }
 };
 
diff --git a/src/providers/data_provider/dp_iface.h b/src/providers/data_provider/dp_iface.h
index 8ae7a2ad7..759b9e6c9 100644
--- a/src/providers/data_provider/dp_iface.h
+++ b/src/providers/data_provider/dp_iface.h
@@ -76,4 +76,8 @@ errno_t dp_failover_list_servers(struct sbus_request *sbus_req,
                                  void *dp_cli,
                                  const char *service_name);
 
+/* org.freedesktop.sssd.DataProvider.AccessControl */
+errno_t dp_access_control_refresh_rules_handler(struct sbus_request *sbus_req,
+                                                void *dp_cli);
+
 #endif /* DP_IFACE_H_ */
diff --git a/src/providers/data_provider/dp_iface.xml b/src/providers/data_provider/dp_iface.xml
index a3969873a..2bfa9dfa7 100644
--- a/src/providers/data_provider/dp_iface.xml
+++ b/src/providers/data_provider/dp_iface.xml
@@ -32,6 +32,12 @@
         </method>
     </interface>
 
+    <interface name="org.freedesktop.sssd.DataProvider.AccessControl">
+        <annotation value="iface_dp_access_control" name="org.freedesktop.DBus.GLib.CSymbol"/>
+        <method name="RefreshRules">
+        </method>
+    </interface>
+
     <interface name="org.freedesktop.sssd.dataprovider">
         <annotation value="iface_dp" name="org.freedesktop.DBus.GLib.CSymbol"/>
         <method name="pamHandler">
diff --git a/src/providers/data_provider/dp_iface_generated.c b/src/providers/data_provider/dp_iface_generated.c
index e2e0216bd..11ee2e24a 100644
--- a/src/providers/data_provider/dp_iface_generated.c
+++ b/src/providers/data_provider/dp_iface_generated.c
@@ -187,6 +187,33 @@ const struct sbus_interface_meta iface_dp_failover_meta = {
     sbus_invoke_get_all, /* GetAll invoker */
 };
 
+int iface_dp_access_control_RefreshRules_finish(struct sbus_request *req)
+{
+   return sbus_request_return_and_finish(req,
+                                         DBUS_TYPE_INVALID);
+}
+
+/* methods for org.freedesktop.sssd.DataProvider.AccessControl */
+const struct sbus_method_meta iface_dp_access_control__methods[] = {
+    {
+        "RefreshRules", /* name */
+        NULL, /* no in_args */
+        NULL, /* no out_args */
+        offsetof(struct iface_dp_access_control, RefreshRules),
+        NULL, /* no invoker */
+    },
+    { NULL, }
+};
+
+/* interface info for org.freedesktop.sssd.DataProvider.AccessControl */
+const struct sbus_interface_meta iface_dp_access_control_meta = {
+    "org.freedesktop.sssd.DataProvider.AccessControl", /* name */
+    iface_dp_access_control__methods,
+    NULL, /* no signals */
+    NULL, /* no properties */
+    sbus_invoke_get_all, /* GetAll invoker */
+};
+
 /* arguments for org.freedesktop.sssd.dataprovider.autofsHandler */
 const struct sbus_arg_meta iface_dp_autofsHandler__in[] = {
     { "dp_flags", "u" },
diff --git a/src/providers/data_provider/dp_iface_generated.h b/src/providers/data_provider/dp_iface_generated.h
index b7f63fb43..541a90b0b 100644
--- a/src/providers/data_provider/dp_iface_generated.h
+++ b/src/providers/data_provider/dp_iface_generated.h
@@ -26,6 +26,10 @@
 #define IFACE_DP_FAILOVER_ACTIVESERVER "ActiveServer"
 #define IFACE_DP_FAILOVER_LISTSERVERS "ListServers"
 
+/* constants for org.freedesktop.sssd.DataProvider.AccessControl */
+#define IFACE_DP_ACCESS_CONTROL "org.freedesktop.sssd.DataProvider.AccessControl"
+#define IFACE_DP_ACCESS_CONTROL_REFRESHRULES "RefreshRules"
+
 /* constants for org.freedesktop.sssd.dataprovider */
 #define IFACE_DP "org.freedesktop.sssd.dataprovider"
 #define IFACE_DP_PAMHANDLER "pamHandler"
@@ -88,6 +92,15 @@ int iface_dp_failover_ActiveServer_finish(struct sbus_request *req, const char *
 /* finish function for ListServers */
 int iface_dp_failover_ListServers_finish(struct sbus_request *req, const char *arg_servers[], int len_servers);
 
+/* vtable for org.freedesktop.sssd.DataProvider.AccessControl */
+struct iface_dp_access_control {
+    struct sbus_vtable vtable; /* derive from sbus_vtable */
+    int (*RefreshRules)(struct sbus_request *req, void *data);
+};
+
+/* finish function for RefreshRules */
+int iface_dp_access_control_RefreshRules_finish(struct sbus_request *req);
+
 /* vtable for org.freedesktop.sssd.dataprovider */
 struct iface_dp {
     struct sbus_vtable vtable; /* derive from sbus_vtable */
@@ -130,6 +143,9 @@ extern const struct sbus_interface_meta iface_dp_backend_meta;
 /* interface info for org.freedesktop.sssd.DataProvider.Failover */
 extern const struct sbus_interface_meta iface_dp_failover_meta;
 
+/* interface info for org.freedesktop.sssd.DataProvider.AccessControl */
+extern const struct sbus_interface_meta iface_dp_access_control_meta;
+
 /* interface info for org.freedesktop.sssd.dataprovider */
 extern const struct sbus_interface_meta iface_dp_meta;
 
diff --git a/src/providers/data_provider/dp_target_auth.c b/src/providers/data_provider/dp_target_auth.c
index 6bb3313b2..4b4797556 100644
--- a/src/providers/data_provider/dp_target_auth.c
+++ b/src/providers/data_provider/dp_target_auth.c
@@ -306,3 +306,17 @@ void dp_pam_handler_selinux_done(struct tevent_req *req)
     dp_pam_reply(state->sbus_req, state->request_name, pd);
     return;
 }
+
+errno_t dp_access_control_refresh_rules_handler(struct sbus_request *sbus_req,
+                                                void *dp_cli)
+{
+    const char *key;
+
+    key = "RefreshRules";
+
+    dp_req_with_reply(dp_cli, NULL, "Refresh Access Control Rules", key,
+                      sbus_req, DPT_ACCESS, DPM_REFRESH_ACCESS_RULES, 0, NULL,
+                      dp_req_reply_default, void *);
+
+    return EOK;
+}

From ebbcbd80e91a50cbd521a42e8601a96cb0538d9c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <[email protected]>
Date: Thu, 2 Nov 2017 14:59:19 +0100
Subject: [PATCH 4/6] ipa: implement method to refresh HBAC rules

---
 src/providers/ipa/ipa_access.c | 69 ++++++++++++++++++++++++++++++++++++++++--
 src/providers/ipa/ipa_access.h | 10 ++++++
 src/providers/ipa/ipa_init.c   |  4 +++
 3 files changed, 81 insertions(+), 2 deletions(-)

diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c
index 32ccf541c..110cde26b 100644
--- a/src/providers/ipa/ipa_access.c
+++ b/src/providers/ipa/ipa_access.c
@@ -682,8 +682,8 @@ static void ipa_pam_access_handler_done(struct tevent_req *subreq)
 
 errno_t
 ipa_pam_access_handler_recv(TALLOC_CTX *mem_ctx,
-                             struct tevent_req *req,
-                             struct pam_data **_data)
+                            struct tevent_req *req,
+                            struct pam_data **_data)
 {
     struct ipa_pam_access_handler_state *state = NULL;
 
@@ -695,3 +695,68 @@ ipa_pam_access_handler_recv(TALLOC_CTX *mem_ctx,
 
     return EOK;
 }
+
+struct ipa_refresh_access_rules_state {
+    int dummy;
+};
+
+static void ipa_refresh_access_rules_done(struct tevent_req *subreq);
+
+struct tevent_req *
+ipa_refresh_access_rules_send(TALLOC_CTX *mem_ctx,
+                              struct ipa_access_ctx *access_ctx,
+                              void *no_input_data,
+                              struct dp_req_params *params)
+{
+    struct ipa_refresh_access_rules_state *state;
+    struct tevent_req *subreq;
+    struct tevent_req *req;
+    errno_t ret;
+
+    DEBUG(SSSDBG_TRACE_FUNC, "Refreshing HBAC rules\n");
+
+    req = tevent_req_create(mem_ctx, &state,
+                            struct ipa_refresh_access_rules_state);
+    if (req == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n");
+        return NULL;
+    }
+
+    subreq = ipa_fetch_hbac_send(state, params->ev, params->be_ctx, access_ctx);
+    if (subreq == NULL) {
+        tevent_req_error(req, ret);
+        tevent_req_post(req, params->ev);
+        return req;
+    }
+
+    tevent_req_set_callback(subreq, ipa_refresh_access_rules_done, req);
+
+    return req;
+}
+
+static void ipa_refresh_access_rules_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req;
+    errno_t ret;
+
+    req = tevent_req_callback_data(subreq, struct tevent_req);
+
+    ret = ipa_fetch_hbac_recv(subreq);
+    talloc_zfree(subreq);
+    if (ret != EOK) {
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    tevent_req_done(req);
+    return;
+}
+
+errno_t ipa_refresh_access_rules_recv(TALLOC_CTX *mem_ctx,
+                                      struct tevent_req *req,
+                                      void **_no_output_data)
+{
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    return EOK;
+}
diff --git a/src/providers/ipa/ipa_access.h b/src/providers/ipa/ipa_access.h
index de6903502..9cec0d106 100644
--- a/src/providers/ipa/ipa_access.h
+++ b/src/providers/ipa/ipa_access.h
@@ -63,4 +63,14 @@ ipa_pam_access_handler_recv(TALLOC_CTX *mem_ctx,
                              struct tevent_req *req,
                              struct pam_data **_data);
 
+struct tevent_req *
+ipa_refresh_access_rules_send(TALLOC_CTX *mem_ctx,
+                              struct ipa_access_ctx *access_ctx,
+                              void *no_input_data,
+                              struct dp_req_params *params);
+
+errno_t ipa_refresh_access_rules_recv(TALLOC_CTX *mem_ctx,
+                                      struct tevent_req *req,
+                                      void **_no_output_data);
+
 #endif /* _IPA_ACCESS_H_ */
diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c
index 5b7c8e134..f335d51fd 100644
--- a/src/providers/ipa/ipa_init.c
+++ b/src/providers/ipa/ipa_init.c
@@ -831,6 +831,10 @@ errno_t sssm_ipa_access_init(TALLOC_CTX *mem_ctx,
                   ipa_pam_access_handler_send, ipa_pam_access_handler_recv, access_ctx,
                   struct ipa_access_ctx, struct pam_data, struct pam_data *);
 
+    dp_set_method(dp_methods, DPM_REFRESH_ACCESS_RULES,
+                      ipa_refresh_access_rules_send, ipa_refresh_access_rules_recv, access_ctx,
+                      struct ipa_access_ctx, void, void *);
+
     ret = EOK;
 
 done:

From 6fa34c0a763b816d95edfae7f06295687af2843d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <[email protected]>
Date: Thu, 2 Nov 2017 14:59:57 +0100
Subject: [PATCH 5/6] ifp: add method to refresh access control rules in domain

---
 src/responder/ifp/ifp_domains.c         | 22 ++++++++++++++++++++++
 src/responder/ifp/ifp_domains.h         |  3 +++
 src/responder/ifp/ifp_iface.c           |  3 ++-
 src/responder/ifp/ifp_iface.xml         |  3 +++
 src/responder/ifp/ifp_iface_generated.c | 13 +++++++++++++
 src/responder/ifp/ifp_iface_generated.h |  5 +++++
 6 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/src/responder/ifp/ifp_domains.c b/src/responder/ifp/ifp_domains.c
index 977bbfcbe..cd7e2fc7a 100644
--- a/src/responder/ifp/ifp_domains.c
+++ b/src/responder/ifp/ifp_domains.c
@@ -630,3 +630,25 @@ int ifp_domains_domain_list_servers(struct sbus_request *sbus_req,
 
     return EOK;
 }
+
+int ifp_domains_domain_refresh_access_rules(struct sbus_request *sbus_req,
+                                            void *data)
+{
+    struct ifp_ctx *ifp_ctx;
+    struct sss_domain_info *dom;
+
+    ifp_ctx = talloc_get_type(data, struct ifp_ctx);
+
+    dom = get_domain_info_from_req(sbus_req, data);
+    if (dom == NULL) {
+        sbus_request_reply_error(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN,
+                                 "Unknown domain");
+        return EOK;
+    }
+
+    rdp_message_send_and_reply(sbus_req, ifp_ctx->rctx, dom, DP_PATH,
+                               IFACE_DP_ACCESS_CONTROL,
+                               IFACE_DP_ACCESS_CONTROL_REFRESHRULES);
+
+    return EOK;
+}
diff --git a/src/responder/ifp/ifp_domains.h b/src/responder/ifp/ifp_domains.h
index 621ba6158..d8cc9d34c 100644
--- a/src/responder/ifp/ifp_domains.h
+++ b/src/responder/ifp/ifp_domains.h
@@ -108,4 +108,7 @@ int ifp_domains_domain_list_servers(struct sbus_request *sbus_req,
                                     void *data,
                                     const char *service);
 
+int ifp_domains_domain_refresh_access_rules(struct sbus_request *sbus_req,
+                                            void *data);
+
 #endif /* IFP_DOMAINS_H_ */
diff --git a/src/responder/ifp/ifp_iface.c b/src/responder/ifp/ifp_iface.c
index 3293b92d7..f995e28f9 100644
--- a/src/responder/ifp/ifp_iface.c
+++ b/src/responder/ifp/ifp_iface.c
@@ -79,7 +79,8 @@ struct iface_ifp_domains_domain iface_ifp_domains_domain = {
     .IsOnline = ifp_domains_domain_is_online,
     .ListServices = ifp_domains_domain_list_services,
     .ActiveServer = ifp_domains_domain_active_server,
-    .ListServers = ifp_domains_domain_list_servers
+    .ListServers = ifp_domains_domain_list_servers,
+    .RefreshAccessRules = ifp_domains_domain_refresh_access_rules
 };
 
 struct iface_ifp_users iface_ifp_users = {
diff --git a/src/responder/ifp/ifp_iface.xml b/src/responder/ifp/ifp_iface.xml
index 39385e866..1aa7eac03 100644
--- a/src/responder/ifp/ifp_iface.xml
+++ b/src/responder/ifp/ifp_iface.xml
@@ -112,6 +112,9 @@
             <arg name="service_name" type="s" direction="in" />
             <arg name="servers" type="as" direction="out" />
         </method>
+
+        <method name="RefreshAccessRules">
+        </method>
     </interface>
 
     <interface name="org.freedesktop.sssd.infopipe.Cache">
diff --git a/src/responder/ifp/ifp_iface_generated.c b/src/responder/ifp/ifp_iface_generated.c
index 6943e38e3..c2cdbf5b0 100644
--- a/src/responder/ifp/ifp_iface_generated.c
+++ b/src/responder/ifp/ifp_iface_generated.c
@@ -552,6 +552,12 @@ int iface_ifp_domains_domain_ListServers_finish(struct sbus_request *req, const
                                          DBUS_TYPE_INVALID);
 }
 
+int iface_ifp_domains_domain_RefreshAccessRules_finish(struct sbus_request *req)
+{
+   return sbus_request_return_and_finish(req,
+                                         DBUS_TYPE_INVALID);
+}
+
 /* methods for org.freedesktop.sssd.infopipe.Domains.Domain */
 const struct sbus_method_meta iface_ifp_domains_domain__methods[] = {
     {
@@ -582,6 +588,13 @@ const struct sbus_method_meta iface_ifp_domains_domain__methods[] = {
         offsetof(struct iface_ifp_domains_domain, ListServers),
         invoke_s_method,
     },
+    {
+        "RefreshAccessRules", /* name */
+        NULL, /* no in_args */
+        NULL, /* no out_args */
+        offsetof(struct iface_ifp_domains_domain, RefreshAccessRules),
+        NULL, /* no invoker */
+    },
     { NULL, }
 };
 
diff --git a/src/responder/ifp/ifp_iface_generated.h b/src/responder/ifp/ifp_iface_generated.h
index 30752bf06..f1e6c80ba 100644
--- a/src/responder/ifp/ifp_iface_generated.h
+++ b/src/responder/ifp/ifp_iface_generated.h
@@ -57,6 +57,7 @@
 #define IFACE_IFP_DOMAINS_DOMAIN_LISTSERVICES "ListServices"
 #define IFACE_IFP_DOMAINS_DOMAIN_ACTIVESERVER "ActiveServer"
 #define IFACE_IFP_DOMAINS_DOMAIN_LISTSERVERS "ListServers"
+#define IFACE_IFP_DOMAINS_DOMAIN_REFRESHACCESSRULES "RefreshAccessRules"
 
 /* constants for org.freedesktop.sssd.infopipe.Cache */
 #define IFACE_IFP_CACHE "org.freedesktop.sssd.infopipe.Cache"
@@ -209,6 +210,7 @@ struct iface_ifp_domains_domain {
     int (*ListServices)(struct sbus_request *req, void *data);
     int (*ActiveServer)(struct sbus_request *req, void *data, const char *arg_service);
     int (*ListServers)(struct sbus_request *req, void *data, const char *arg_service_name);
+    int (*RefreshAccessRules)(struct sbus_request *req, void *data);
 };
 
 /* finish function for IsOnline */
@@ -223,6 +225,9 @@ int iface_ifp_domains_domain_ActiveServer_finish(struct sbus_request *req, const
 /* finish function for ListServers */
 int iface_ifp_domains_domain_ListServers_finish(struct sbus_request *req, const char *arg_servers[], int len_servers);
 
+/* finish function for RefreshAccessRules */
+int iface_ifp_domains_domain_RefreshAccessRules_finish(struct sbus_request *req);
+
 /* vtable for org.freedesktop.sssd.infopipe.Cache */
 struct iface_ifp_cache {
     struct sbus_vtable vtable; /* derive from sbus_vtable */

From 9c756c634e5647bbc4db9a1f1eb344c971c3923a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <[email protected]>
Date: Thu, 2 Nov 2017 15:00:17 +0100
Subject: [PATCH 6/6] sssctl: call dbus instead of pam to refresh HBAC rules

---
 src/tools/sssctl/sssctl_access_report.c | 125 ++++++++++++++------------------
 1 file changed, 56 insertions(+), 69 deletions(-)

diff --git a/src/tools/sssctl/sssctl_access_report.c b/src/tools/sssctl/sssctl_access_report.c
index 111723298..25889f582 100644
--- a/src/tools/sssctl/sssctl_access_report.c
+++ b/src/tools/sssctl/sssctl_access_report.c
@@ -15,11 +15,11 @@
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include <security/pam_appl.h>
-
 #include "util/util.h"
 #include "tools/common/sss_tools.h"
 #include "tools/sssctl/sssctl.h"
+#include "sbus/sssd_dbus.h"
+#include "responder/ifp/ifp_iface.h"
 
 /*
  * We're searching the cache directly..
@@ -27,58 +27,9 @@
 #include "providers/ipa/ipa_hbac_private.h"
 #include "providers/ipa/ipa_rules_common.h"
 
-#ifdef HAVE_SECURITY_PAM_MISC_H
-# include <security/pam_misc.h>
-#elif defined(HAVE_SECURITY_OPENPAM_H)
-# include <security/openpam.h>
-#endif
-
-#ifdef HAVE_SECURITY_PAM_MISC_H
-static struct pam_conv conv = {
-    misc_conv,
-    NULL
-};
-#elif defined(HAVE_SECURITY_OPENPAM_H)
-static struct pam_conv conv = {
-    openpam_ttyconv,
-    NULL
-};
-#else
-# error "Missing text based pam conversation function"
-#endif
-
-#ifndef DEFAULT_SERVICE
-#define DEFAULT_SERVICE "system-auth"
-#endif /* DEFAULT_SERVICE */
-
-#ifndef DEFAULT_USER
-#define DEFAULT_USER "admin"
-#endif /* DEFAULT_USER */
-
 typedef errno_t (*sssctl_dom_access_reporter_fn)(struct sss_tool_ctx *tool_ctx,
-                                                 const char *user,
-                                                 const char *service,
                                                  struct sss_domain_info *domain);
 
-static errno_t run_pam_acct(struct sss_tool_ctx *tool_ctx,
-                            const char *user,
-                            const char *service,
-                            struct sss_domain_info *domain)
-{
-    errno_t ret;
-    pam_handle_t *pamh;
-
-    ret = pam_start(service, user, &conv, &pamh);
-    if (ret != PAM_SUCCESS) {
-        ERROR("pam_start failed: %s\n", pam_strerror(pamh, ret));
-        return EIO;
-    }
-
-    ret = pam_acct_mgmt(pamh, 0);
-    pam_end(pamh, ret);
-    return ret;
-}
-
 static errno_t get_rdn_value(TALLOC_CTX *mem_ctx,
                              struct sss_domain_info *dom,
                              const char *dn_attr,
@@ -315,9 +266,56 @@ static void print_ipa_hbac_rule(struct sss_domain_info *domain,
     PRINT("\n");
 }
 
+static errno_t refresh_hbac_rules(struct sss_tool_ctx *tool_ctx,
+                                  struct sss_domain_info *domain)
+{
+    TALLOC_CTX *tmp_ctx;
+    sss_sifp_error error;
+    sss_sifp_ctx *sifp;
+    DBusMessage *reply;
+    const char *path;
+    errno_t ret;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+        return ENOMEM;
+    }
+
+    path = sbus_opath_compose(tool_ctx, IFP_PATH_DOMAINS, domain->name);
+    if (path == NULL) {
+        printf(_("Out of memory!\n"));
+        return ENOMEM;
+    }
+
+    error = sssctl_sifp_init(tool_ctx, &sifp);
+    if (error != SSS_SIFP_OK) {
+        sssctl_sifp_error(sifp, error, "Unable to connect to the InfoPipe");
+        goto done;
+    }
+
+    error = sssctl_sifp_send(tmp_ctx, sifp, &reply, path,
+                             IFACE_IFP_DOMAINS_DOMAIN,
+                             IFACE_IFP_DOMAINS_DOMAIN_REFRESHACCESSRULES);
+    if (error != SSS_SIFP_OK) {
+        sssctl_sifp_error(sifp, error, "Unable to refresh HBAC rules");
+        ret = EIO;
+        goto done;
+    }
+
+    ret = sbus_parse_reply(reply);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    ret = EOK;
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
 static errno_t sssctl_ipa_access_report(struct sss_tool_ctx *tool_ctx,
-                                        const char *user,
-                                        const char *service,
                                         struct sss_domain_info *domain)
 {
     TALLOC_CTX *tmp_ctx = NULL;
@@ -338,9 +336,9 @@ static errno_t sssctl_ipa_access_report(struct sss_tool_ctx *tool_ctx,
     struct ldb_message **msgs = NULL;
 
     /* Run the pam account phase to make sure the rules are fetched by SSSD */
-    ret = run_pam_acct(tool_ctx, user, service, domain);
-    if (ret != PAM_SUCCESS && ret != PAM_PERM_DENIED) {
-        ERROR("Cannot run the PAM account phase, reporting stale rules\n");
+    ret = refresh_hbac_rules(tool_ctx, domain);
+    if (ret != EOK) {
+        ERROR("Unable to refresh HBAC rules, using cached content\n");
         /* Non-fatal */
     }
 
@@ -398,19 +396,8 @@ errno_t sssctl_access_report(struct sss_cmdline *cmdline,
     const char *domname = NULL;
     sssctl_dom_access_reporter_fn reporter;
     struct sss_domain_info *dom;
-    const char *user = DEFAULT_USER;
-    const char *service = DEFAULT_SERVICE;
-
-    /* Parse command line. */
-    struct poptOption options[] = {
-        { "user", 'u', POPT_ARG_STRING, &user, 0,
-          _("PAM user, default: " DEFAULT_USER), NULL },
-        { "service", 's', POPT_ARG_STRING, &service, 0,
-          _("PAM service, default: " DEFAULT_SERVICE), NULL },
-        POPT_TABLEEND
-    };
 
-    ret = sss_tool_popt_ex(cmdline, options, SSS_TOOL_OPT_OPTIONAL,
+    ret = sss_tool_popt_ex(cmdline, NULL, SSS_TOOL_OPT_OPTIONAL,
                            NULL, NULL, "DOMAIN", _("Specify domain name."),
                            &domname, NULL);
     if (ret != EOK) {
@@ -431,5 +418,5 @@ errno_t sssctl_access_report(struct sss_cmdline *cmdline,
         return ret;
     }
 
-    return reporter(tool_ctx, user, service, dom);
+    return reporter(tool_ctx, dom);
 }
_______________________________________________
sssd-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to