From 10c52176a4ae8b0ffd206bb040156dc166f8dac8 Mon Sep 17 00:00:00 2001
From: Petr Cech <pcech@redhat.com>
Date: Tue, 23 Feb 2016 10:11:15 -0500
Subject: [PATCH 2/2] TOOL: Invalidation of sudo rules at sss_cache

This patch adds new functionality to sss_cach for invalidation of given
sudo rule or all sudo rules.

Resolves:
https://fedorahosted.org/sssd/ticket/2081
---
 src/man/sss_cache.8.xml | 23 +++++++++++++++++
 src/tools/sss_cache.c   | 65 ++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 85 insertions(+), 3 deletions(-)

diff --git a/src/man/sss_cache.8.xml b/src/man/sss_cache.8.xml
index 1bc3633d9daa69ea59ba7ada0b6e180ece6e508a..81489288ced92ee5d4e7608ac092924369292bca 100644
--- a/src/man/sss_cache.8.xml
+++ b/src/man/sss_cache.8.xml
@@ -180,6 +180,29 @@
                     </para>
                 </listitem>
             </varlistentry>
+           <varlistentry condition="with_sudo">
+                <term>
+                    <option>-r</option>,<option>--sudo-rule</option>
+                    <replaceable>rule</replaceable>
+                </term>
+                <listitem>
+                    <para>
+                        Invalidate particular sudo rule.
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry condition="with_sudo">
+                <term>
+                    <option>-R</option>,<option>--sudo-rules</option>
+                </term>
+                <listitem>
+                    <para>
+                        Invalidate all cached sudo rules. This option
+                        overrides invalidation of specific sudo rule
+                        if it was also set.
+                    </para>
+                </listitem>
+            </varlistentry>
             <varlistentry>
                 <term>
                     <option>-d</option>,<option>--domain</option>
diff --git a/src/tools/sss_cache.c b/src/tools/sss_cache.c
index 88895e8de374ed3fe16cbc92125ee3b91172e39e..8788ab7d53ae4ea66c5820d7fcddedb6761a021b 100644
--- a/src/tools/sss_cache.c
+++ b/src/tools/sss_cache.c
@@ -31,6 +31,7 @@
 #include "db/sysdb_services.h"
 #include "db/sysdb_autofs.h"
 #include "db/sysdb_ssh.h"
+#include "db/sysdb_sudo.h"
 
 #define INVALIDATE_NONE 0
 #define INVALIDATE_USERS 1
@@ -39,6 +40,7 @@
 #define INVALIDATE_SERVICES 8
 #define INVALIDATE_AUTOFSMAPS 16
 #define INVALIDATE_SSH_HOSTS 32
+#define INVALIDATE_SUDO_RULES 64
 
 #ifdef BUILD_AUTOFS
 #ifdef BUILD_SSH
@@ -67,7 +69,8 @@ enum sss_cache_entry {
     TYPE_NETGROUP,
     TYPE_SERVICE,
     TYPE_AUTOFSMAP,
-    TYPE_SSH_HOST
+    TYPE_SSH_HOST,
+    TYPE_SUDO_RULE
 };
 
 static errno_t search_autofsmaps(TALLOC_CTX *mem_ctx,
@@ -85,6 +88,7 @@ struct cache_tool_ctx {
     char *service_filter;
     char *autofs_filter;
     char *ssh_host_filter;
+    char *sudo_rule_filter;
 
     char *user_name;
     char *group_name;
@@ -92,6 +96,7 @@ struct cache_tool_ctx {
     char *service_name;
     char *autofs_name;
     char *ssh_host_name;
+    char *sudo_rule_name;
 
     bool update_user_filter;
     bool update_group_filter;
@@ -99,6 +104,7 @@ struct cache_tool_ctx {
     bool update_service_filter;
     bool update_autofs_filter;
     bool update_ssh_host_filter;
+    bool update_sudo_rule_filter;
 };
 
 errno_t init_domains(struct cache_tool_ctx *ctx, const char *domain);
@@ -172,6 +178,9 @@ int main(int argc, const char *argv[])
         skipped &= !invalidate_entries(tctx, dinfo, TYPE_SSH_HOST,
                                        tctx->ssh_host_filter,
                                        tctx->ssh_host_name);
+        skipped &= !invalidate_entries(tctx, dinfo, TYPE_SUDO_RULE,
+                                       tctx->sudo_rule_filter,
+                                       tctx->sudo_rule_name);
 
         ret = sysdb_transaction_commit(sysdb);
         if (ret != EOK) {
@@ -356,6 +365,14 @@ static errno_t update_all_filters(struct cache_tool_ctx *tctx,
         return ret;
     }
 
+    /* Update sudo rule filter */
+    ret = update_filter(tctx, dinfo, tctx->sudo_rule_name,
+                        tctx->update_sudo_rule_filter, "(%s=%s)", false,
+                        &tctx->sudo_rule_filter);
+    if (ret != EOK) {
+        return ret;
+    }
+
     return EOK;
 }
 
@@ -408,6 +425,15 @@ static bool invalidate_entries(TALLOC_CTX *ctx,
         ret = ENOSYS;
 #endif /* BUILD_SSH */
         break;
+    case TYPE_SUDO_RULE:
+        type_string = "sudo_rule";
+#ifdef BUILD_SUDO
+        ret = sysdb_search_sudo_rules(ctx, dinfo,
+                                      filter, attrs, &msg_count, &msgs);
+#else  /* BUILD_SUDO */
+        ret = ENOSYS;
+#endif /* BUILD_SUDO */
+        break;
     }
 
     if (ret != EOK) {
@@ -492,6 +518,14 @@ static errno_t invalidate_entry(TALLOC_CTX *ctx,
                     ret = ENOSYS;
 #endif /* BUILD_SSH */
                     break;
+                case TYPE_SUDO_RULE:
+#ifdef BUILD_SUDO
+                    ret = sysdb_set_sudo_rule_attr(domain, name,
+                                                   sys_attrs, SYSDB_MOD_REP);
+#else  /* BUILD_SUDO */
+                    ret = ENOSYS;
+#endif /* BUILD_SUDO */
+                    break;
                 default:
                     return EINVAL;
             }
@@ -577,6 +611,7 @@ errno_t init_context(int argc, const char *argv[], struct cache_tool_ctx **tctx)
     char *service = NULL;
     char *map = NULL;
     char *ssh_host = NULL;
+    char *sudo_rule = NULL;
     char *domain = NULL;
     int debug = SSSDBG_DEFAULT;
     errno_t ret = EOK;
@@ -616,6 +651,12 @@ errno_t init_context(int argc, const char *argv[], struct cache_tool_ctx **tctx)
         { "ssh-hosts", 'H', POPT_ARG_NONE, NULL, 'h',
             _("Invalidate all SSH hosts"), NULL },
 #endif /* BUILD_SSH */
+#ifdef BUILD_SUDO
+        { "sudo-rule", 'r', POPT_ARG_STRING, &sudo_rule, 0,
+            _("Invalidate particular sudo rule"), NULL },
+        { "sudo-rules", 'R', POPT_ARG_NONE, NULL, 'r',
+            _("Invalidate all cached sudo rules"), NULL },
+#endif /* BUILD_SUDO */
         { "domain", 'd', POPT_ARG_STRING, &domain, 0,
             _("Only invalidate entries from a particular domain"), NULL },
         POPT_TABLEEND
@@ -650,8 +691,12 @@ errno_t init_context(int argc, const char *argv[], struct cache_tool_ctx **tctx)
             case 'h':
                 idb |= INVALIDATE_SSH_HOSTS;
                 break;
+            case 'r':
+                idb |= INVALIDATE_SUDO_RULES;
+                break;
             case 'e':
                 idb = INVALIDATE_EVERYTHING;
+                idb |= INVALIDATE_SUDO_RULES;
                 break;
         }
     }
@@ -664,7 +709,7 @@ errno_t init_context(int argc, const char *argv[], struct cache_tool_ctx **tctx)
     }
 
     if (idb == INVALIDATE_NONE && !user && !group &&
-        !netgroup && !service && !map && !ssh_host) {
+        !netgroup && !service && !map && !ssh_host && !sudo_rule) {
         BAD_POPT_PARAMS(pc,
                 _("Please select at least one object to invalidate\n"),
                 ret, fini);
@@ -729,18 +774,28 @@ errno_t init_context(int argc, const char *argv[], struct cache_tool_ctx **tctx)
         ctx->update_ssh_host_filter = true;
     }
 
+    if (idb & INVALIDATE_SUDO_RULES) {
+        ctx->sudo_rule_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME);
+        ctx->update_sudo_rule_filter = false;
+    } else if (sudo_rule) {
+        ctx->sudo_rule_name = talloc_strdup(ctx, sudo_rule);
+        ctx->update_sudo_rule_filter = true;
+    }
+
     if (((idb & INVALIDATE_USERS) && !ctx->user_filter) ||
         ((idb & INVALIDATE_GROUPS) && !ctx->group_filter) ||
         ((idb & INVALIDATE_NETGROUPS) && !ctx->netgroup_filter) ||
         ((idb & INVALIDATE_SERVICES) && !ctx->service_filter) ||
         ((idb & INVALIDATE_AUTOFSMAPS) && !ctx->autofs_filter) ||
         ((idb & INVALIDATE_SSH_HOSTS) && !ctx->ssh_host_filter) ||
+        ((idb & INVALIDATE_SUDO_RULES) && !ctx->sudo_rule_filter) ||
          (user && !ctx->user_name) ||
          (group && !ctx->group_name) ||
          (netgroup && !ctx->netgroup_name) ||
          (service && !ctx->service_name) ||
          (map && !ctx->autofs_name) ||
-         (ssh_host && !ctx->ssh_host_name)) {
+         (ssh_host && !ctx->ssh_host_name) ||
+         (sudo_rule && !ctx->sudo_rule_name)) {
         DEBUG(SSSDBG_CRIT_FAILURE, "Construction of filters failed\n");
         ret = ENOMEM;
         goto fini;
@@ -768,6 +823,10 @@ fini:
     free(group);
     free(netgroup);
     free(domain);
+    free(service);
+    free(map);
+    free(ssh_host);
+    free(sudo_rule);
     if (ret != EOK && ctx) {
         talloc_zfree(ctx);
     }
-- 
2.5.0

