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 8d36174dad1d69f0241d8e8777eb8ef8f9f6f5f0 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 a6f20c1c2..32ff8d076 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1752,6 +1752,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 36268f25fd1dbde53b5ac60a27c6f5f63fa41eab 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 c243991b4b489704a668c1ff6c5e6d79bcc12068 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 d52be759bbbec45fbfc1b45dfbe7f58e304269fc 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 | 68 ++++++++++++++++++++++++++++++++++++++++-- src/providers/ipa/ipa_access.h | 10 +++++++ src/providers/ipa/ipa_init.c | 4 +++ 3 files changed, 80 insertions(+), 2 deletions(-) diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c index 32ccf541c..de9f68170 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,67 @@ 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; + + 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, ENOMEM); + 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 2ba9900041d6689fd6aa42c3f7388971cb84f986 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 ace32830f63e214d01c0bfb0b52a2fd4e81a2d11 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 | 127 +++++++++++++++----------------- 1 file changed, 58 insertions(+), 69 deletions(-) diff --git a/src/tools/sssctl/sssctl_access_report.c b/src/tools/sssctl/sssctl_access_report.c index 111723298..8cf1a8a87 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,58 @@ 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(tmp_ctx, IFP_PATH_DOMAINS, domain->name); + if (path == NULL) { + printf(_("Out of memory!\n")); + ret = ENOMEM; + goto done; + } + + error = sssctl_sifp_init(tool_ctx, &sifp); + if (error != SSS_SIFP_OK) { + sssctl_sifp_error(sifp, error, "Unable to connect to the InfoPipe"); + ret = EIO; + 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 +338,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 +398,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 +420,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]
