URL: https://github.com/SSSD/sssd/pull/274
Author: justin-stephenson
 Title: #274: Merge sss_cache and sss_debuglevel into sssctl
Action: opened

PR body:
"""
Move `sss_cache` into a new command **sssctl expire-cache** and 
`sss_debuglevel` into new command **sssctl debug-level** for ticket 
https://pagure.io/SSSD/sssd/issue/3057

Shell redirect wrappers replace the `sss_{debuglevel,cache}` binaries and man 
pages updated to point admins towards the new **sssctl** commands.
"""

To pull the PR as Git branch:
git remote add ghsssd https://github.com/SSSD/sssd
git fetch ghsssd pull/274/head:pr274
git checkout pr274
From 31af2027a76cc02fa50f4852924007decafe4b83 Mon Sep 17 00:00:00 2001
From: Justin Stephenson <[email protected]>
Date: Fri, 12 May 2017 14:08:37 -0400
Subject: [PATCH 1/4] SSSCTL: Add sss_cache shell wrapper

The added sss_cache shell wrapper will be used to replace
/usr/sbin/sss_cache binary to merge sss_cache into sssctl. The wrapper
will redirect sss_cache to the sssctl expire-cache command performing
the same task. The sss_cache(8) man page is updated to indicate that
sss_cache is deprecated and functionality exists now in sssctl.

Resolves:
https://pagure.io/SSSD/sssd/issue/3057
---
 Makefile.am                |   2 +
 configure.ac               |   1 +
 contrib/tools/sss_cache.in |   4 +
 src/man/sss_cache.8.xml    | 194 +--------------------------------------------
 4 files changed, 11 insertions(+), 190 deletions(-)
 create mode 100644 contrib/tools/sss_cache.in

diff --git a/Makefile.am b/Makefile.am
index c947e31..491bfe3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -456,6 +456,8 @@ dist_noinst_SCRIPTS = \
     src/tests/krb5_proxy_check_test_data.conf \
     $(NULL)
 
+dist_sbin_SCRIPTS = contrib/tools/sss_cache
+
 dist_noinst_DATA = \
     src/config/testconfigs/sssd-valid.conf \
     src/config/testconfigs/noparse.api.conf \
diff --git a/configure.ac b/configure.ac
index 80d8ea9..1dfa2d2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -504,5 +504,6 @@ AC_CONFIG_FILES([Makefile contrib/sssd.spec src/examples/rwtab src/doxy.config
                  src/lib/sifp/sss_simpleifp.doxy
                  src/config/setup.py
                  src/systemtap/sssd.stp
+                 contrib/tools/sss_cache
                  src/config/SSSDConfig/__init__.py])
 AC_OUTPUT
diff --git a/contrib/tools/sss_cache.in b/contrib/tools/sss_cache.in
new file mode 100644
index 0000000..a576e85
--- /dev/null
+++ b/contrib/tools/sss_cache.in
@@ -0,0 +1,4 @@
+#!/bin/sh
+sbindir=@sbindir@
+echo "Redirecting to $sbindir/sssctl expire-cache"
+$sbindir/sssctl expire-cache $@
diff --git a/src/man/sss_cache.8.xml b/src/man/sss_cache.8.xml
index 221c0a8..6d918ac 100644
--- a/src/man/sss_cache.8.xml
+++ b/src/man/sss_cache.8.xml
@@ -13,7 +13,7 @@
 
     <refnamediv id='name'>
         <refname>sss_cache</refname>
-        <refpurpose>perform cache cleanup</refpurpose>
+        <refpurpose>[DEPRECATED] perform cache cleanup</refpurpose>
     </refnamediv>
 
     <refsynopsisdiv id='synopsis'>
@@ -28,198 +28,12 @@
     <refsect1 id='description'>
         <title>DESCRIPTION</title>
         <para>
-            <command>sss_cache</command> invalidates records in SSSD cache.
-            Invalidated records are forced to be reloaded from server as soon
-            as related SSSD backend is online. Options that invalidate a single
-            object only accept a single provided argument.
+            <command>sss_cache</command> is deprecated and replaced by
+            the sssctl expire-cache command. Please refer to the
+            <command>sssctl(8)</command> man page for more information on sssctl usage.
         </para>
     </refsect1>
 
-    <refsect1 id='options'>
-        <title>OPTIONS</title>
-        <variablelist remap='IP'>
-            <varlistentry>
-                <term>
-                    <option>-E</option>,<option>--everything</option>
-                </term>
-                <listitem>
-                    <para>
-                        Invalidate all cached entries.
-                    </para>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>
-                    <option>-u</option>,<option>--user</option>
-                    <replaceable>login</replaceable>
-                </term>
-                <listitem>
-                    <para>
-                        Invalidate specific user.
-                    </para>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>
-                    <option>-U</option>,<option>--users</option>
-                </term>
-                <listitem>
-                    <para>
-                        Invalidate all user records. This option overrides
-                        invalidation of specific user if it was also set.
-                    </para>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>
-                    <option>-g</option>,<option>--group</option>
-                    <replaceable>group</replaceable>
-                </term>
-                <listitem>
-                    <para>
-                        Invalidate specific group.
-                    </para>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>
-                    <option>-G</option>,<option>--groups</option>
-                </term>
-                <listitem>
-                    <para>
-                        Invalidate all group records. This option overrides
-                        invalidation of specific group if it was also set.
-                    </para>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>
-                    <option>-n</option>,<option>--netgroup</option>
-                    <replaceable>netgroup</replaceable>
-                </term>
-                <listitem>
-                    <para>
-                        Invalidate specific netgroup.
-                    </para>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>
-                    <option>-N</option>,<option>--netgroups</option>
-                </term>
-                <listitem>
-                    <para>
-                        Invalidate all netgroup records. This option overrides
-                        invalidation of specific netgroup if it was also set.
-                    </para>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>
-                    <option>-s</option>,<option>--service</option>
-                    <replaceable>service</replaceable>
-                </term>
-                <listitem>
-                    <para>
-                        Invalidate specific service.
-                    </para>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>
-                    <option>-S</option>,<option>--services</option>
-                </term>
-                <listitem>
-                    <para>
-                        Invalidate all service records. This option overrides
-                        invalidation of specific service if it was also set.
-                    </para>
-                </listitem>
-            </varlistentry>
-            <varlistentry condition="with_autofs">
-                <term>
-                    <option>-a</option>,<option>--autofs-map</option>
-                    <replaceable>autofs-map</replaceable>
-                </term>
-                <listitem>
-                    <para>
-                        Invalidate specific autofs maps.
-                    </para>
-                </listitem>
-            </varlistentry>
-            <varlistentry condition="with_autofs">
-                <term>
-                    <option>-A</option>,<option>--autofs-maps</option>
-                </term>
-                <listitem>
-                    <para>
-                        Invalidate all autofs maps. This option overrides
-                        invalidation of specific map if it was also set.
-                    </para>
-                </listitem>
-            </varlistentry>
-            <varlistentry condition="with_ssh">
-                <term>
-                    <option>-h</option>,<option>--ssh-host</option>
-                    <replaceable>hostname</replaceable>
-                </term>
-                <listitem>
-                    <para>
-                        Invalidate SSH public keys of a specific host.
-                    </para>
-                </listitem>
-            </varlistentry>
-            <varlistentry condition="with_ssh">
-                <term>
-                    <option>-H</option>,<option>--ssh-hosts</option>
-                </term>
-                <listitem>
-                    <para>
-                        Invalidate SSH public keys of all hosts. This option
-                        overrides invalidation of SSH public keys of specific
-                        host if it was also set.
-                    </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>
-                    <replaceable>domain</replaceable>
-                </term>
-                <listitem>
-                    <para>
-                        Restrict invalidation process only to a particular
-                        domain.
-                    </para>
-                </listitem>
-            </varlistentry>
-            <xi:include xmlns:xi="http://www.w3.org/2001/XInclude"; href="include/param_help.xml" />
-        </variablelist>
-    </refsect1>
-
     <xi:include xmlns:xi="http://www.w3.org/2001/XInclude"; href="include/seealso.xml" />
 
 </refentry>

From 6ad70639aa884fabde1dcf966d40b5530c8bd5c3 Mon Sep 17 00:00:00 2001
From: Justin Stephenson <[email protected]>
Date: Fri, 12 May 2017 17:08:08 -0400
Subject: [PATCH 2/4] SSSCTL: Move sss_cache into sssctl expire-cache

Move code from sss_cache to sssctl_cache and add new expire-cache sssctl
command to perform the same invalidation of cache objects.

POPT_CONTEXT_KEEP_FIRST Flag added to poptGetContext call in
init_context() to fix argument parsing.

Resolves:
https://pagure.io/SSSD/sssd/issue/3057
---
 Makefile.am                     |  13 +-
 po/POTFILES.in                  |   1 -
 src/tools/common/sss_tools.c    |   6 -
 src/tools/common/sss_tools.h    |   7 +-
 src/tools/sss_cache.c           | 962 ----------------------------------------
 src/tools/sssctl/sssctl.c       |   3 +-
 src/tools/sssctl/sssctl.h       |   4 +
 src/tools/sssctl/sssctl_cache.c | 916 ++++++++++++++++++++++++++++++++++++++
 8 files changed, 930 insertions(+), 982 deletions(-)
 delete mode 100644 src/tools/sss_cache.c

diff --git a/Makefile.am b/Makefile.am
index 491bfe3..73b3153 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -141,7 +141,6 @@ sbin_PROGRAMS = \
     sss_usermod \
     sss_groupmod \
     sss_groupshow \
-    sss_cache \
     sss_debuglevel \
     sss_override \
     sss_seed \
@@ -1672,15 +1671,6 @@ sss_groupshow_LDADD = \
     $(TOOLS_LIBS) \
     $(SSSD_INTERNAL_LTLIBS)
 
-sss_cache_SOURCES = \
-    src/tools/sss_cache.c \
-    $(SSSD_LCL_TOOLS_OBJ)
-sss_cache_LDADD = \
-    $(TOOLS_LIBS) \
-    $(SSSD_INTERNAL_LTLIBS) \
-    $(CLIENT_LIBS)
-sss_cache_CFLAGS = $(AM_CFLAGS)
-
 sss_debuglevel_SOURCES = \
     src/tools/sss_debuglevel.c \
     $(SSSD_TOOLS_OBJ)
@@ -1727,7 +1717,7 @@ sssctl_SOURCES = \
     src/tools/sssctl/sssctl_sifp.c \
     src/tools/sssctl/sssctl_config.c \
     src/tools/sssctl/sssctl_user_checks.c \
-    $(SSSD_TOOLS_OBJ) \
+    $(SSSD_LCL_TOOLS_OBJ) \
     $(NULL)
 sssctl_LDADD = \
     $(TOOLS_LIBS) \
@@ -1735,6 +1725,7 @@ sssctl_LDADD = \
     $(PAM_LIBS) \
     $(PAM_MISC_LIBS) \
     $(LIBADD_DL) \
+    $(CLIENTS_LIBS) \
     libsss_simpleifp.la \
     $(NULL)
 sssctl_CFLAGS = \
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 33e7ed7..b928473 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -19,7 +19,6 @@ src/tools/sss_groupshow.c
 src/tools/sss_useradd.c
 src/tools/sss_userdel.c
 src/tools/sss_usermod.c
-src/tools/sss_cache.c
 src/tools/sss_debuglevel.c
 src/tools/tools_util.c
 src/tools/tools_util.h
diff --git a/src/tools/common/sss_tools.c b/src/tools/common/sss_tools.c
index 97a3caa..d6ae726 100644
--- a/src/tools/common/sss_tools.c
+++ b/src/tools/common/sss_tools.c
@@ -30,12 +30,6 @@
 #include "db/sysdb.h"
 #include "tools/common/sss_tools.h"
 
-struct sss_cmdline {
-    const char *exec; /* argv[0] */
-    const char *command; /* command name */
-    int argc; /* rest of arguments */
-    const char **argv;
-};
 
 static void sss_tool_print_common_opts(int min_len)
 {
diff --git a/src/tools/common/sss_tools.h b/src/tools/common/sss_tools.h
index 49da7d6..8480093 100644
--- a/src/tools/common/sss_tools.h
+++ b/src/tools/common/sss_tools.h
@@ -38,7 +38,12 @@ errno_t sss_tool_init(TALLOC_CTX *mem_ctx,
                       int *argc, const char **argv,
                       struct sss_tool_ctx **_tool_ctx);
 
-struct sss_cmdline;
+struct sss_cmdline {
+    const char *exec; /* argv[0] */
+    const char *command; /* command name */
+    int argc; /* rest of arguments */
+    const char **argv;
+};
 
 typedef errno_t
 (*sss_route_fn)(struct sss_cmdline *cmdline,
diff --git a/src/tools/sss_cache.c b/src/tools/sss_cache.c
deleted file mode 100644
index 8a40b38..0000000
--- a/src/tools/sss_cache.c
+++ /dev/null
@@ -1,962 +0,0 @@
-/*
-   SSSD
-
-   sss_cache
-
-   Copyright (C) Jan Zeleny <[email protected]>        2011
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <talloc.h>
-#include <popt.h>
-#include <sys/types.h>
-
-#include "util/util.h"
-#include "tools/sss_sync_ops.h"
-#include "db/sysdb.h"
-#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
-#define INVALIDATE_GROUPS 2
-#define INVALIDATE_NETGROUPS 4
-#define INVALIDATE_SERVICES 8
-#define INVALIDATE_AUTOFSMAPS 16
-#define INVALIDATE_SSH_HOSTS 32
-#define INVALIDATE_SUDO_RULES 64
-
-#ifdef BUILD_AUTOFS
-#ifdef BUILD_SSH
-#define INVALIDATE_EVERYTHING (INVALIDATE_USERS | INVALIDATE_GROUPS | \
-                               INVALIDATE_NETGROUPS | INVALIDATE_SERVICES | \
-                               INVALIDATE_AUTOFSMAPS | INVALIDATE_SSH_HOSTS )
-#else  /* BUILD_SSH */
-#define INVALIDATE_EVERYTHING (INVALIDATE_USERS | INVALIDATE_GROUPS | \
-                               INVALIDATE_NETGROUPS | INVALIDATE_SERVICES | \
-                               INVALIDATE_AUTOFSMAPS )
-#endif /* BUILD_SSH */
-#else  /* BUILD_AUTOFS */
-#ifdef BUILD_SSH
-#define INVALIDATE_EVERYTHING (INVALIDATE_USERS | INVALIDATE_GROUPS | \
-                               INVALIDATE_NETGROUPS | INVALIDATE_SERVICES | \
-                               INVALIDATE_SSH_HOSTS )
-#else  /* BUILD_SSH */
-#define INVALIDATE_EVERYTHING (INVALIDATE_USERS | INVALIDATE_GROUPS | \
-                               INVALIDATE_NETGROUPS | INVALIDATE_SERVICES )
-#endif /* BUILD_SSH */
-#endif /* BUILD_AUTOFS */
-
-enum sss_cache_entry {
-    TYPE_USER=0,
-    TYPE_GROUP,
-    TYPE_NETGROUP,
-    TYPE_SERVICE,
-    TYPE_AUTOFSMAP,
-    TYPE_SSH_HOST,
-    TYPE_SUDO_RULE
-};
-
-static errno_t search_autofsmaps(TALLOC_CTX *mem_ctx,
-                                 struct sss_domain_info *domain,
-                                 const char *sub_filter, const char **attrs,
-                                 size_t *msgs_count, struct ldb_message ***msgs);
-
-struct input_values {
-    char *domain;
-    char *group;
-    char *map;
-    char *netgroup;
-    char *service;
-    char *ssh_host;
-    char *sudo_rule;
-    char *user;
-};
-
-struct cache_tool_ctx {
-    struct confdb_ctx *confdb;
-    struct sss_domain_info *domains;
-
-    char *user_filter;
-    char *group_filter;
-    char *netgroup_filter;
-    char *service_filter;
-    char *autofs_filter;
-    char *ssh_host_filter;
-    char *sudo_rule_filter;
-
-    char *user_name;
-    char *group_name;
-    char *netgroup_name;
-    char *service_name;
-    char *autofs_name;
-    char *ssh_host_name;
-    char *sudo_rule_name;
-
-    bool update_user_filter;
-    bool update_group_filter;
-    bool update_netgroup_filter;
-    bool update_service_filter;
-    bool update_autofs_filter;
-    bool update_ssh_host_filter;
-    bool update_sudo_rule_filter;
-};
-
-static void free_input_values(struct input_values *values);
-static bool is_filter_valid(struct cache_tool_ctx *ctx,
-                            struct input_values *values, int idb);
-static errno_t init_domains(struct cache_tool_ctx *ctx,
-                            const char *domain);
-static errno_t init_context(int argc, const char *argv[],
-                            struct cache_tool_ctx **tctx);
-static errno_t invalidate_entry(TALLOC_CTX *ctx,
-                                struct sss_domain_info *domain,
-                                const char *name, int entry_type);
-static bool invalidate_entries(TALLOC_CTX *ctx,
-                               struct sss_domain_info *dinfo,
-                               enum sss_cache_entry entry_type,
-                               const char *filter, const char *name);
-static errno_t update_all_filters(struct cache_tool_ctx *tctx,
-                                  struct sss_domain_info *dinfo);
-static int sysdb_invalidate_user_cache_entry(struct sss_domain_info *domain,
-                                             const char *name);
-static int sysdb_invalidate_group_cache_entry(struct sss_domain_info *domain,
-                                              const char *name);
-
-int main(int argc, const char *argv[])
-{
-    errno_t ret;
-    struct cache_tool_ctx *tctx = NULL;
-    struct sysdb_ctx *sysdb;
-    bool skipped = true;
-    struct sss_domain_info *dinfo;
-
-    ret = init_context(argc, argv, &tctx);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "Error initializing context for the application\n");
-        goto done;
-    }
-
-    for (dinfo = tctx->domains; dinfo;
-            dinfo = get_next_domain(dinfo, SSS_GND_DESCEND)) {
-        if (!IS_SUBDOMAIN(dinfo)) {
-            /* Update list of subdomains for this domain */
-            ret = sysdb_update_subdomains(dinfo, tctx->confdb);
-            if (ret != EOK) {
-                DEBUG(SSSDBG_MINOR_FAILURE,
-                      "Failed to update subdomains for domain %s.\n", dinfo->name);
-            }
-        }
-
-        sysdb = dinfo->sysdb;
-        /* Update filters for each domain */
-        ret = update_all_filters(tctx, dinfo);
-        if (ret != EOK) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "Failed to update filters.\n");
-            goto done;
-        }
-
-        ret = sysdb_transaction_start(sysdb);
-        if (ret != EOK) {
-            DEBUG(SSSDBG_CRIT_FAILURE,
-                  "Could not start the transaction!\n");
-            goto done;
-        }
-
-        skipped &= !invalidate_entries(tctx, dinfo, TYPE_USER,
-                                       tctx->user_filter,
-                                       tctx->user_name);
-        skipped &= !invalidate_entries(tctx, dinfo, TYPE_GROUP,
-                                       tctx->group_filter,
-                                       tctx->group_name);
-        skipped &= !invalidate_entries(tctx, dinfo, TYPE_NETGROUP,
-                                       tctx->netgroup_filter,
-                                       tctx->netgroup_name);
-        skipped &= !invalidate_entries(tctx, dinfo, TYPE_SERVICE,
-                                       tctx->service_filter,
-                                       tctx->service_name);
-        skipped &= !invalidate_entries(tctx, dinfo, TYPE_AUTOFSMAP,
-                                       tctx->autofs_filter,
-                                       tctx->autofs_name);
-        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) {
-            DEBUG(SSSDBG_CRIT_FAILURE,
-                  "Could not commit the transaction!\n");
-            ret = sysdb_transaction_cancel(sysdb);
-            if (ret != EOK) {
-                DEBUG(SSSDBG_CRIT_FAILURE,
-                      "Failed to cancel transaction\n");
-            }
-        }
-    }
-
-    if (skipped == true) {
-        ERROR("No cache object matched the specified search\n");
-        ret = ENOENT;
-        goto done;
-    } else {
-        ret = sss_memcache_clear_all();
-        if (ret != EOK) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "Failed to clear memory cache.\n");
-            goto done;
-        }
-    }
-
-    ret = EOK;
-done:
-    if (tctx) talloc_free(tctx);
-    return ret;
-}
-
-static void free_input_values(struct input_values *values)
-{
-    free(values->domain);
-    free(values->group);
-    free(values->map);
-    free(values->netgroup);
-    free(values->service);
-    free(values->ssh_host);
-    free(values->sudo_rule);
-    free(values->user);
-}
-
-static errno_t update_filter(struct cache_tool_ctx *tctx,
-                             struct sss_domain_info *dinfo,
-                             char *name, bool update, const char *fmt,
-                             enum sss_cache_entry entry_type,
-                             bool force_case_sensitivity,
-                             char **_filter)
-{
-    errno_t ret;
-    char *parsed_domain = NULL;
-    char *parsed_name = NULL;
-    TALLOC_CTX *tmp_ctx = NULL;
-    char *use_name = NULL;
-    char *filter;
-    char *sanitized;
-    char *lc_sanitized;
-
-    if (!name || !update) {
-        /* Nothing to do */
-        return EOK;
-    }
-
-    tmp_ctx = talloc_new(NULL);
-    if (tmp_ctx == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory.\n");
-        return ENOMEM;
-    }
-
-    ret = sss_parse_name(tmp_ctx, dinfo->names, name,
-                         &parsed_domain, &parsed_name);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "sss_parse_name failed\n");
-        goto done;
-    }
-
-    if (parsed_domain != NULL && strcasecmp(dinfo->name, parsed_domain) != 0) {
-        /* We were able to parse the domain from given fqdn, but it
-         * does not match with currently processed domain. */
-        filter = NULL;
-        ret = EOK;
-        goto done;
-    }
-
-    if (!dinfo->case_sensitive && !force_case_sensitivity) {
-        use_name = sss_tc_utf8_str_tolower(tmp_ctx, parsed_name);
-        if (!use_name) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory\n");
-            ret = ENOMEM;
-            goto done;
-        }
-    } else {
-        use_name = parsed_name;
-    }
-
-    switch (entry_type) {
-        case TYPE_USER:
-        case TYPE_GROUP:
-            use_name = sss_create_internal_fqname(tmp_ctx, use_name, dinfo->name);
-        default:
-            break;
-    }
-    if (!use_name) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    ret = sss_filter_sanitize_for_dom(tmp_ctx, use_name, dinfo,
-                                      &sanitized, &lc_sanitized);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to sanitize the given name.\n");
-        goto done;
-    }
-
-    if (fmt) {
-        if (!dinfo->case_sensitive && !force_case_sensitivity) {
-            filter = talloc_asprintf(tmp_ctx, "(|(%s=%s)(%s=%s))",
-                                     SYSDB_NAME_ALIAS, lc_sanitized,
-                                     SYSDB_NAME_ALIAS, sanitized);
-        } else {
-            filter = talloc_asprintf(tmp_ctx, fmt, SYSDB_NAME, sanitized);
-        }
-    } else {
-        filter = talloc_strdup(tmp_ctx, sanitized);
-    }
-    if (filter == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory\n");
-        ret = ENOMEM;
-        goto done;
-    }
-
-    ret = EOK;
-
-done:
-    if (ret == EOK) {
-        talloc_free(*_filter);
-        *_filter = talloc_steal(tctx, filter);
-    }
-
-    talloc_free(tmp_ctx);
-    return ret;
-
-}
-
-/* This function updates all filters for specified domain using this
- * domains regex to parse string into domain and name (if exists). */
-static errno_t update_all_filters(struct cache_tool_ctx *tctx,
-                                  struct sss_domain_info *dinfo)
-{
-    errno_t ret;
-
-    /* Update user filter */
-    ret = update_filter(tctx, dinfo, tctx->user_name,
-                        tctx->update_user_filter, "(%s=%s)",
-                        TYPE_USER, false,
-                        &tctx->user_filter);
-    if (ret != EOK) {
-        return ret;
-    }
-
-    /* Update group filter */
-    ret = update_filter(tctx, dinfo, tctx->group_name,
-                        tctx->update_group_filter, "(%s=%s)",
-                        TYPE_GROUP, false,
-                        &tctx->group_filter);
-    if (ret != EOK) {
-        return ret;
-    }
-
-    /* Update netgroup filter */
-    ret = update_filter(tctx, dinfo, tctx->netgroup_name,
-                        tctx->update_netgroup_filter, "(%s=%s)",
-                        TYPE_NETGROUP, false,
-                        &tctx->netgroup_filter);
-    if (ret != EOK) {
-        return ret;
-    }
-
-    /* Update service filter */
-    ret = update_filter(tctx, dinfo, tctx->service_name,
-                        tctx->update_service_filter, "(%s=%s)",
-                        TYPE_SERVICE, false,
-                        &tctx->service_filter);
-    if (ret != EOK) {
-        return ret;
-    }
-
-    /* Update autofs filter */
-    ret = update_filter(tctx, dinfo, tctx->autofs_name,
-                        tctx->update_autofs_filter,
-                        "(&(objectclass="SYSDB_AUTOFS_MAP_OC")(%s=%s))",
-                        TYPE_AUTOFSMAP, true,
-                        &tctx->autofs_filter);
-    if (ret != EOK) {
-        return ret;
-    }
-
-    /* Update ssh host filter */
-    ret = update_filter(tctx, dinfo, tctx->ssh_host_name,
-                        tctx->update_ssh_host_filter, "(%s=%s)",
-                        TYPE_SSH_HOST, false,
-                        &tctx->ssh_host_filter);
-    if (ret != EOK) {
-        return ret;
-    }
-
-    /* Update sudo rule filter */
-    ret = update_filter(tctx, dinfo, tctx->sudo_rule_name,
-                        tctx->update_sudo_rule_filter,
-                        "(%s=%s)", TYPE_SUDO_RULE, false,
-                        &tctx->sudo_rule_filter);
-    if (ret != EOK) {
-        return ret;
-    }
-
-    return EOK;
-}
-
-static bool invalidate_entries(TALLOC_CTX *ctx,
-                               struct sss_domain_info *dinfo,
-                               enum sss_cache_entry entry_type,
-                               const char *filter, const char *name)
-{
-    const char *attrs[] = {SYSDB_NAME, NULL};
-    size_t msg_count;
-    struct ldb_message **msgs;
-    const char *type_string = "unknown";
-    errno_t ret = EINVAL;
-    int i;
-    const char *c_name;
-    bool iret;
-
-    if (!filter) return false;
-    switch (entry_type) {
-    case TYPE_USER:
-        type_string = "user";
-        ret = sysdb_search_users(ctx, dinfo,
-                                 filter, attrs, &msg_count, &msgs);
-        break;
-    case TYPE_GROUP:
-        type_string = "group";
-        ret = sysdb_search_groups(ctx, dinfo,
-                                  filter, attrs, &msg_count, &msgs);
-        break;
-    case TYPE_NETGROUP:
-        type_string = "netgroup";
-        ret = sysdb_search_netgroups(ctx, dinfo,
-                                     filter, attrs, &msg_count, &msgs);
-        break;
-    case TYPE_SERVICE:
-        type_string = "service";
-        ret = sysdb_search_services(ctx, dinfo,
-                                    filter, attrs, &msg_count, &msgs);
-        break;
-    case TYPE_AUTOFSMAP:
-        type_string = "autofs map";
-        ret = search_autofsmaps(ctx, dinfo, filter, attrs, &msg_count, &msgs);
-        break;
-    case TYPE_SSH_HOST:
-        type_string = "ssh_host";
-#ifdef BUILD_SSH
-        ret = sysdb_search_ssh_hosts(ctx, dinfo,
-                                     filter, attrs, &msg_count, &msgs);
-#else  /* BUILD_SSH */
-        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) {
-        if (ret == ENOENT) {
-            DEBUG(SSSDBG_TRACE_FUNC, "'%s' %s: Not found in domain '%s'\n",
-                  type_string, name ? name : "", dinfo->name);
-        } else {
-            DEBUG(SSSDBG_CRIT_FAILURE,
-                  "Searching for %s in domain %s with filter %s failed\n",
-                   type_string, dinfo->name, filter);
-        }
-        return false;
-    }
-
-    iret = true;
-    for (i = 0; i < msg_count; i++) {
-        c_name = ldb_msg_find_attr_as_string(msgs[i], SYSDB_NAME, NULL);
-        if (c_name == NULL) {
-            DEBUG(SSSDBG_MINOR_FAILURE,
-                  "Something bad happened, can't find attribute %s\n",
-                  SYSDB_NAME);
-            ERROR("Couldn't invalidate %1$s\n", type_string);
-            iret = false;
-        } else {
-            ret = invalidate_entry(ctx, dinfo, c_name, entry_type);
-            if (ret != EOK) {
-                DEBUG(SSSDBG_MINOR_FAILURE,
-                      "Couldn't invalidate %s %s\n", type_string, c_name);
-                ERROR("Couldn't invalidate %1$s %2$s\n", type_string, c_name);
-                iret = false;
-            }
-        }
-    }
-    talloc_zfree(msgs);
-    return iret;
-}
-
-static errno_t invalidate_entry(TALLOC_CTX *ctx,
-                                struct sss_domain_info *domain,
-                                const char *name, int entry_type)
-{
-    struct sysdb_attrs *sys_attrs = NULL;
-    errno_t ret;
-
-    sys_attrs = sysdb_new_attrs(ctx);
-    if (sys_attrs) {
-        ret = sysdb_attrs_add_time_t(sys_attrs,
-                SYSDB_CACHE_EXPIRE, 1);
-        if (ret == EOK) {
-            switch (entry_type) {
-                case TYPE_USER:
-                    /* For users, we also need to reset the initgroups
-                     * cache expiry */
-                    ret = sysdb_attrs_add_time_t(sys_attrs,
-                            SYSDB_INITGR_EXPIRE, 1);
-                    if (ret != EOK) return ret;
-
-                    ret = sysdb_set_user_attr(domain, name, sys_attrs,
-                                              SYSDB_MOD_REP);
-                    if (ret != EOK) break;
-
-                    /* WARNING: Direct writing to persistent cache!! */
-                    ret = sysdb_invalidate_user_cache_entry(domain, name);
-                    break;
-                case TYPE_GROUP:
-                    ret = sysdb_set_group_attr(domain, name, sys_attrs,
-                                               SYSDB_MOD_REP);
-                    if (ret != EOK) break;
-
-                    /* WARNING: Direct writing to persistent cache!! */
-                    ret = sysdb_invalidate_group_cache_entry(domain, name);
-                    break;
-                case TYPE_NETGROUP:
-                    ret = sysdb_set_netgroup_attr(domain, name, sys_attrs,
-                                                  SYSDB_MOD_REP);
-                    break;
-                case TYPE_SERVICE:
-                    ret = sysdb_set_service_attr(domain, name,
-                                                 sys_attrs, SYSDB_MOD_REP);
-                    break;
-                case TYPE_AUTOFSMAP:
-                    ret = sysdb_set_autofsmap_attr(domain, name,
-                                                   sys_attrs, SYSDB_MOD_REP);
-                    break;
-                case TYPE_SSH_HOST:
-#ifdef BUILD_SSH
-                    ret = sysdb_set_ssh_host_attr(domain, name,
-                                                  sys_attrs, SYSDB_MOD_REP);
-#else  /* BUILD_SSH */
-                    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;
-            }
-            if (ret != EOK) {
-                DEBUG(SSSDBG_MINOR_FAILURE, "Could not set entry attributes\n");
-            }
-        } else {
-            DEBUG(SSSDBG_MINOR_FAILURE,
-                  "Could not add expiration time to attributes\n");
-        }
-        talloc_zfree(sys_attrs);
-    } else {
-        DEBUG(SSSDBG_MINOR_FAILURE, "Could not create sysdb attributes\n");
-        ret = ENOMEM;
-    }
-    return ret;
-}
-
-static errno_t init_domains(struct cache_tool_ctx *ctx,
-                            const char *domain)
-{
-    char *confdb_path;
-    int ret;
-    struct sss_domain_info *dinfo;
-
-    confdb_path = talloc_asprintf(ctx, "%s/%s", DB_PATH, CONFDB_FILE);
-    if (confdb_path == NULL) {
-        return ENOMEM;
-    }
-
-    /* Connect to the conf db */
-    ret = confdb_init(ctx, &ctx->confdb, confdb_path);
-    talloc_free(confdb_path);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "Could not initialize connection to the confdb\n");
-        return ret;
-    }
-
-    if (domain) {
-        ret = sssd_domain_init(ctx, ctx->confdb,
-                               domain, DB_PATH, &ctx->domains);
-        if (ret != EOK) {
-            SYSDB_VERSION_ERROR(ret);
-            DEBUG(SSSDBG_CRIT_FAILURE,
-                  "Could not initialize connection to the sysdb\n");
-            return ret;
-        }
-
-    } else {
-        ret = confdb_get_domains(ctx->confdb, &ctx->domains);
-        if (ret != EOK) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "Could not initialize domains\n");
-            return ret;
-        }
-
-        ret = sysdb_init(ctx, ctx->domains);
-        SYSDB_VERSION_ERROR(ret);
-        if (ret != EOK) {
-            DEBUG(SSSDBG_CRIT_FAILURE,
-                  "Could not initialize connection to the sysdb\n");
-            return ret;
-        }
-    }
-
-    for (dinfo = ctx->domains; dinfo; dinfo = get_next_domain(dinfo, 0)) {
-        ret = sss_names_init(ctx, ctx->confdb, dinfo->name, &dinfo->names);
-        if (ret != EOK) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "sss_names_init() failed\n");
-            return ret;
-        }
-    }
-
-    return EOK;
-}
-
-static errno_t init_context(int argc, const char *argv[],
-                            struct cache_tool_ctx **tctx)
-{
-    struct cache_tool_ctx *ctx = NULL;
-    int idb = INVALIDATE_NONE;
-    struct input_values values = { 0 };
-    int debug = SSSDBG_DEFAULT;
-    errno_t ret = EOK;
-
-    poptContext pc = NULL;
-    struct poptOption long_options[] = {
-        POPT_AUTOHELP
-        { "debug", '\0', POPT_ARG_INT | POPT_ARGFLAG_DOC_HIDDEN, &debug,
-            0, _("The debug level to run with"), NULL },
-        { "everything", 'E', POPT_ARG_NONE, NULL, 'e',
-            _("Invalidate all cached entries"), NULL },
-        { "user", 'u', POPT_ARG_STRING, &(values.user), 0,
-            _("Invalidate particular user"), NULL },
-        { "users", 'U', POPT_ARG_NONE, NULL, 'u',
-            _("Invalidate all users"), NULL },
-        { "group", 'g', POPT_ARG_STRING, &(values.group), 0,
-            _("Invalidate particular group"), NULL },
-        { "groups", 'G', POPT_ARG_NONE, NULL, 'g',
-            _("Invalidate all groups"), NULL },
-        { "netgroup", 'n', POPT_ARG_STRING, &(values.netgroup), 0,
-            _("Invalidate particular netgroup"), NULL },
-        { "netgroups", 'N', POPT_ARG_NONE, NULL, 'n',
-            _("Invalidate all netgroups"), NULL },
-        { "service", 's', POPT_ARG_STRING, &(values.service), 0,
-            _("Invalidate particular service"), NULL },
-        { "services", 'S', POPT_ARG_NONE, NULL, 's',
-            _("Invalidate all services"), NULL },
-#ifdef BUILD_AUTOFS
-        { "autofs-map", 'a', POPT_ARG_STRING, &(values.map), 0,
-            _("Invalidate particular autofs map"), NULL },
-        { "autofs-maps", 'A', POPT_ARG_NONE, NULL, 'a',
-            _("Invalidate all autofs maps"), NULL },
-#endif /* BUILD_AUTOFS */
-#ifdef BUILD_SSH
-        { "ssh-host", 'h', POPT_ARG_STRING, &(values.ssh_host), 0,
-            _("Invalidate particular SSH host"), NULL },
-        { "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, &(values.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, &(values.domain), 0,
-            _("Only invalidate entries from a particular domain"), NULL },
-        POPT_TABLEEND
-    };
-
-    ret = set_locale();
-    if (ret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "set_locale failed (%d): %s\n", ret, strerror(ret));
-        ERROR("Error setting the locale\n");
-        goto fini;
-    }
-
-    pc = poptGetContext(NULL, argc, argv, long_options, 0);
-    while ((ret = poptGetNextOpt(pc)) > 0) {
-        switch (ret) {
-            case 'u':
-                idb |= INVALIDATE_USERS;
-                break;
-            case 'g':
-                idb |= INVALIDATE_GROUPS;
-                break;
-            case 'n':
-                idb |= INVALIDATE_NETGROUPS;
-                break;
-            case 's':
-                idb |= INVALIDATE_SERVICES;
-                break;
-            case 'a':
-                idb |= INVALIDATE_AUTOFSMAPS;
-                break;
-            case 'h':
-                idb |= INVALIDATE_SSH_HOSTS;
-                break;
-            case 'r':
-                idb |= INVALIDATE_SUDO_RULES;
-                break;
-            case 'e':
-                idb = INVALIDATE_EVERYTHING;
-#ifdef BUILD_SUDO
-                idb |= INVALIDATE_SUDO_RULES;
-#endif /* BUILD_SUDO */
-                break;
-        }
-    }
-
-    DEBUG_CLI_INIT(debug);
-    debug_prg_name = argv[0];
-
-    if (ret != -1) {
-        BAD_POPT_PARAMS(pc, poptStrerror(ret), ret, fini);
-    }
-
-    if (poptGetArg(pc)) {
-        BAD_POPT_PARAMS(pc,
-                _("Unexpected argument(s) provided, options that "
-                  "invalidate a single object only accept a single "
-                  "provided argument.\n"),
-                  ret, fini);
-    }
-
-    if (idb == INVALIDATE_NONE && !values.user && !values.group &&
-        !values.netgroup && !values.service && !values.map &&
-        !values.ssh_host && !values.sudo_rule) {
-        BAD_POPT_PARAMS(pc,
-                _("Please select at least one object to invalidate\n"),
-                ret, fini);
-    }
-
-    CHECK_ROOT(ret, debug_prg_name);
-
-    ctx = talloc_zero(NULL, struct cache_tool_ctx);
-    if (ctx == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "Could not allocate memory for tools context\n");
-        ret = ENOMEM;
-        goto fini;
-    }
-
-    if (idb & INVALIDATE_USERS) {
-        ctx->user_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME);
-        ctx->update_user_filter = false;
-    } else if (values.user) {
-        ctx->user_name = talloc_strdup(ctx, values.user);
-        ctx->update_user_filter = true;
-    }
-
-    if (idb & INVALIDATE_GROUPS) {
-        ctx->group_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME);
-        ctx->update_group_filter = false;
-    } else if (values.group) {
-        ctx->group_name = talloc_strdup(ctx, values.group);
-        ctx->update_group_filter = true;
-    }
-
-    if (idb & INVALIDATE_NETGROUPS) {
-        ctx->netgroup_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME);
-        ctx->update_netgroup_filter = false;
-    } else if (values.netgroup) {
-        ctx->netgroup_name = talloc_strdup(ctx, values.netgroup);
-        ctx->update_netgroup_filter = true;
-    }
-
-    if (idb & INVALIDATE_SERVICES) {
-        ctx->service_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME);
-        ctx->update_service_filter = false;
-    } else if (values.service) {
-        ctx->service_name = talloc_strdup(ctx, values.service);
-        ctx->update_service_filter = true;
-    }
-
-    if (idb & INVALIDATE_AUTOFSMAPS) {
-        ctx->autofs_filter = talloc_asprintf(ctx, "(&(objectclass=%s)(%s=*))",
-                                             SYSDB_AUTOFS_MAP_OC, SYSDB_NAME);
-        ctx->update_autofs_filter = false;
-    } else if (values.map) {
-        ctx->autofs_name = talloc_strdup(ctx, values.map);
-        ctx->update_autofs_filter = true;
-    }
-
-    if (idb & INVALIDATE_SSH_HOSTS) {
-        ctx->ssh_host_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME);
-        ctx->update_ssh_host_filter = false;
-    } else if (values.ssh_host) {
-        ctx->ssh_host_name = talloc_strdup(ctx, values.ssh_host);
-        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 (values.sudo_rule) {
-        ctx->sudo_rule_name = talloc_strdup(ctx, values.sudo_rule);
-        ctx->update_sudo_rule_filter = true;
-    }
-
-    if (is_filter_valid(ctx, &values, idb) == false) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Construction of filters failed\n");
-        ret = ENOMEM;
-        goto fini;
-    }
-
-    ret = init_domains(ctx, values.domain);
-    if (ret != EOK) {
-        if (values.domain) {
-            ERROR("Could not open domain %1$s. If the domain is a subdomain "
-                  "(trusted domain), use fully qualified name instead of "
-                  "--domain/-d parameter.\n", values.domain);
-        } else {
-            ERROR("Could not open available domains\n");
-        }
-        DEBUG(SSSDBG_OP_FAILURE,
-              "Initialization of sysdb connections failed\n");
-        goto fini;
-    }
-
-    ret = EOK;
-
-fini:
-    poptFreeContext(pc);
-    free_input_values(&values);
-    if (ret != EOK && ctx) {
-        talloc_zfree(ctx);
-    }
-    if (ret == EOK) {
-        *tctx = ctx;
-    }
-    return ret;
-}
-
-static bool is_filter_valid(struct cache_tool_ctx *ctx,
-                            struct input_values *values, int idb)
-{
-    if ((idb & INVALIDATE_USERS) && ctx->user_filter == NULL) {
-        return false;
-    }
-
-    if ((idb & INVALIDATE_GROUPS) && ctx->group_filter == NULL) {
-        return false;
-    }
-
-    if ((idb & INVALIDATE_NETGROUPS) && ctx->netgroup_filter == NULL) {
-        return false;
-    }
-
-    if ((idb & INVALIDATE_SERVICES) && ctx->service_filter == NULL) {
-        return false;
-    }
-
-    if ((idb & INVALIDATE_AUTOFSMAPS) && ctx->autofs_filter == NULL) {
-        return false;
-    }
-
-    if ((idb & INVALIDATE_SSH_HOSTS) && ctx->ssh_host_filter == NULL) {
-        return false;
-    }
-
-    if (values->user && ctx->user_name == NULL) {
-        return false;
-    }
-
-    if (values->group && ctx->group_name == NULL) {
-        return false;
-    }
-
-    if (values->netgroup && ctx->netgroup_name == NULL) {
-        return false;
-    }
-
-    if (values->service && ctx->service_name == NULL) {
-        return false;
-    }
-
-    if (values->map && ctx->autofs_name == NULL) {
-        return false;
-    }
-
-    if (values->ssh_host && ctx->ssh_host_name == NULL) {
-        return false;
-    }
-
-    if (values->sudo_rule && ctx->sudo_rule_name == NULL) {
-        return false;
-    }
-
-    return true;
-}
-
-static errno_t
-search_autofsmaps(TALLOC_CTX *mem_ctx,
-                  struct sss_domain_info *domain,
-                  const char *sub_filter, const char **attrs,
-                  size_t *msgs_count, struct ldb_message ***msgs)
-{
-#ifdef BUILD_AUTOFS
-    return sysdb_search_custom(mem_ctx, domain, sub_filter,
-                               AUTOFS_MAP_SUBDIR, attrs,
-                               msgs_count, msgs);
-#else
-    return ENOSYS;
-#endif  /* BUILD_AUTOFS */
-}
-
-/* WARNING: Direct writing to persistent cache!! */
-static int sysdb_invalidate_user_cache_entry(struct sss_domain_info *domain,
-                                             const char *name)
-{
-    return sysdb_invalidate_cache_entry(domain, name, true);
-}
-
-/* WARNING: Direct writing to persistent cache!! */
-static int sysdb_invalidate_group_cache_entry(struct sss_domain_info *domain,
-                                              const char *name)
-{
-    return sysdb_invalidate_cache_entry(domain, name, false);
-}
diff --git a/src/tools/sssctl/sssctl.c b/src/tools/sssctl/sssctl.c
index 509d2e1..d0bf752 100644
--- a/src/tools/sssctl/sssctl.c
+++ b/src/tools/sssctl/sssctl.c
@@ -264,10 +264,11 @@ 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_DELIMITER("Information about cached content:"),
+        SSS_TOOL_DELIMITER("Cached Content tools:"),
         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),
         SSS_TOOL_COMMAND("netgroup-show", "Information about cached netgroup", 0, sssctl_netgroup_show),
+        SSS_TOOL_COMMAND("expire-cache", "Invalidate cached objects", 0, sssctl_expire_cache),
         SSS_TOOL_DELIMITER("Local data tools:"),
         SSS_TOOL_COMMAND("client-data-backup", "Backup local data", 0, sssctl_client_data_backup),
         SSS_TOOL_COMMAND("client-data-restore", "Restore local data from backup", 0, sssctl_client_data_restore),
diff --git a/src/tools/sssctl/sssctl.h b/src/tools/sssctl/sssctl.h
index 22626e2..dd7e039 100644
--- a/src/tools/sssctl/sssctl.h
+++ b/src/tools/sssctl/sssctl.h
@@ -118,6 +118,10 @@ errno_t sssctl_netgroup_show(struct sss_cmdline *cmdline,
                              struct sss_tool_ctx *tool_ctx,
                              void *pvt);
 
+errno_t sssctl_expire_cache(struct sss_cmdline *cmdline,
+                             struct sss_tool_ctx *tool_ctx,
+                             void *pvt);
+
 errno_t sssctl_config_check(struct sss_cmdline *cmdline,
                             struct sss_tool_ctx *tool_ctx,
                             void *pvt);
diff --git a/src/tools/sssctl/sssctl_cache.c b/src/tools/sssctl/sssctl_cache.c
index 8f0fc28..cc75f00 100644
--- a/src/tools/sssctl/sssctl_cache.c
+++ b/src/tools/sssctl/sssctl_cache.c
@@ -22,11 +22,19 @@
 #include <stdio.h>
 #include <time.h>
 #include <errno.h>
+#include <stdlib.h>
+#include <talloc.h>
+#include <sys/types.h>
 
 #include "util/util.h"
 #include "db/sysdb.h"
+#include "db/sysdb_services.h"
+#include "db/sysdb_autofs.h"
+#include "db/sysdb_ssh.h"
+#include "db/sysdb_sudo.h"
 #include "tools/common/sss_tools.h"
 #include "tools/sssctl/sssctl.h"
+#include "tools/sss_sync_ops.h"
 
 #define NOT_FOUND_MSG(obj) _(obj " %s is not present in cache.\n")
 
@@ -37,12 +45,52 @@
 #define SSSCTL_CACHE_IFP    {_("Cached in InfoPipe"), SYSDB_IFP_CACHED, attr_yesno}
 #define SSSCTL_CACHE_NULL   {NULL, NULL, NULL}
 
+#define INVALIDATE_NONE 0
+#define INVALIDATE_USERS 1
+#define INVALIDATE_GROUPS 2
+#define INVALIDATE_NETGROUPS 4
+#define INVALIDATE_SERVICES 8
+#define INVALIDATE_AUTOFSMAPS 16
+#define INVALIDATE_SSH_HOSTS 32
+#define INVALIDATE_SUDO_RULES 64
+
+#ifdef BUILD_AUTOFS
+#ifdef BUILD_SSH
+#define INVALIDATE_EVERYTHING (INVALIDATE_USERS | INVALIDATE_GROUPS | \
+                               INVALIDATE_NETGROUPS | INVALIDATE_SERVICES | \
+                               INVALIDATE_AUTOFSMAPS | INVALIDATE_SSH_HOSTS )
+#else  /* BUILD_SSH */
+#define INVALIDATE_EVERYTHING (INVALIDATE_USERS | INVALIDATE_GROUPS | \
+                               INVALIDATE_NETGROUPS | INVALIDATE_SERVICES | \
+                               INVALIDATE_AUTOFSMAPS )
+#endif /* BUILD_SSH */
+#else  /* BUILD_AUTOFS */
+#ifdef BUILD_SSH
+#define INVALIDATE_EVERYTHING (INVALIDATE_USERS | INVALIDATE_GROUPS | \
+                               INVALIDATE_NETGROUPS | INVALIDATE_SERVICES | \
+                               INVALIDATE_SSH_HOSTS )
+#else  /* BUILD_SSH */
+#define INVALIDATE_EVERYTHING (INVALIDATE_USERS | INVALIDATE_GROUPS | \
+                               INVALIDATE_NETGROUPS | INVALIDATE_SERVICES )
+#endif /* BUILD_SSH */
+#endif /* BUILD_AUTOFS */
+
 enum cache_object {
     CACHED_USER,
     CACHED_GROUP,
     CACHED_NETGROUP,
 };
 
+enum sss_cache_entry {
+    TYPE_USER=0,
+    TYPE_GROUP,
+    TYPE_NETGROUP,
+    TYPE_SERVICE,
+    TYPE_AUTOFSMAP,
+    TYPE_SSH_HOST,
+    TYPE_SUDO_RULE
+};
+
 typedef errno_t (*sssctl_attr_fn)(TALLOC_CTX *mem_ctx,
                                   struct sysdb_attrs *entry,
                                   struct sss_domain_info *dom,
@@ -58,6 +106,779 @@ struct sssctl_object_info {
     sssctl_attr_fn attr_fn;
 };
 
+struct input_values {
+    char *domain;
+    char *group;
+    char *map;
+    char *netgroup;
+    char *service;
+    char *ssh_host;
+    char *sudo_rule;
+    char *user;
+};
+
+struct cache_tool_ctx {
+    struct confdb_ctx *confdb;
+    struct sss_domain_info *domains;
+
+    char *user_filter;
+    char *group_filter;
+    char *netgroup_filter;
+    char *service_filter;
+    char *autofs_filter;
+    char *ssh_host_filter;
+    char *sudo_rule_filter;
+
+    char *user_name;
+    char *group_name;
+    char *netgroup_name;
+    char *service_name;
+    char *autofs_name;
+    char *ssh_host_name;
+    char *sudo_rule_name;
+
+    bool update_user_filter;
+    bool update_group_filter;
+    bool update_netgroup_filter;
+    bool update_service_filter;
+    bool update_autofs_filter;
+    bool update_ssh_host_filter;
+    bool update_sudo_rule_filter;
+};
+
+static void free_input_values(struct input_values *values)
+{
+    free(values->domain);
+    free(values->group);
+    free(values->map);
+    free(values->netgroup);
+    free(values->service);
+    free(values->ssh_host);
+    free(values->sudo_rule);
+    free(values->user);
+}
+
+static errno_t
+search_autofsmaps(TALLOC_CTX *mem_ctx,
+                  struct sss_domain_info *domain,
+                  const char *sub_filter, const char **attrs,
+                  size_t *msgs_count, struct ldb_message ***msgs)
+{
+#ifdef BUILD_AUTOFS
+    return sysdb_search_custom(mem_ctx, domain, sub_filter,
+                               AUTOFS_MAP_SUBDIR, attrs,
+                               msgs_count, msgs);
+#else
+    return ENOSYS;
+#endif  /* BUILD_AUTOFS */
+}
+
+/* WARNING: Direct writing to persistent cache!! */
+static int sysdb_invalidate_user_cache_entry(struct sss_domain_info *domain,
+                                             const char *name)
+{
+    return sysdb_invalidate_cache_entry(domain, name, true);
+}
+
+/* WARNING: Direct writing to persistent cache!! */
+static int sysdb_invalidate_group_cache_entry(struct sss_domain_info *domain,
+                                              const char *name)
+{
+    return sysdb_invalidate_cache_entry(domain, name, false);
+}
+
+static errno_t update_filter(struct cache_tool_ctx *tctx,
+                             struct sss_domain_info *dinfo,
+                             char *name, bool update, const char *fmt,
+                             enum sss_cache_entry entry_type,
+                             bool force_case_sensitivity,
+                             char **_filter)
+{
+    errno_t ret;
+    char *parsed_domain = NULL;
+    char *parsed_name = NULL;
+    TALLOC_CTX *tmp_ctx = NULL;
+    char *use_name = NULL;
+    char *filter;
+    char *sanitized;
+    char *lc_sanitized;
+
+    if (!name || !update) {
+        /* Nothing to do */
+        return EOK;
+    }
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory.\n");
+        return ENOMEM;
+    }
+
+    ret = sss_parse_name(tmp_ctx, dinfo->names, name,
+                         &parsed_domain, &parsed_name);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "sss_parse_name failed\n");
+        goto done;
+    }
+
+    if (parsed_domain != NULL && strcasecmp(dinfo->name, parsed_domain) != 0) {
+        /* We were able to parse the domain from given fqdn, but it
+         * does not match with currently processed domain. */
+        filter = NULL;
+        ret = EOK;
+        goto done;
+    }
+
+    if (!dinfo->case_sensitive && !force_case_sensitivity) {
+        use_name = sss_tc_utf8_str_tolower(tmp_ctx, parsed_name);
+        if (!use_name) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory\n");
+            ret = ENOMEM;
+            goto done;
+        }
+    } else {
+        use_name = parsed_name;
+    }
+
+    switch (entry_type) {
+        case TYPE_USER:
+        case TYPE_GROUP:
+            use_name = sss_create_internal_fqname(tmp_ctx, use_name, dinfo->name);
+        default:
+            break;
+    }
+    if (!use_name) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = sss_filter_sanitize_for_dom(tmp_ctx, use_name, dinfo,
+                                      &sanitized, &lc_sanitized);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to sanitize the given name.\n");
+        goto done;
+    }
+
+    if (fmt) {
+        if (!dinfo->case_sensitive && !force_case_sensitivity) {
+            filter = talloc_asprintf(tmp_ctx, "(|(%s=%s)(%s=%s))",
+                                     SYSDB_NAME_ALIAS, lc_sanitized,
+                                     SYSDB_NAME_ALIAS, sanitized);
+        } else {
+            filter = talloc_asprintf(tmp_ctx, fmt, SYSDB_NAME, sanitized);
+        }
+    } else {
+        filter = talloc_strdup(tmp_ctx, sanitized);
+    }
+    if (filter == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = EOK;
+
+done:
+    if (ret == EOK) {
+        talloc_free(*_filter);
+        *_filter = talloc_steal(tctx, filter);
+    }
+
+    talloc_free(tmp_ctx);
+    return ret;
+
+}
+
+/* This function updates all filters for specified domain using this
+ * domains regex to parse string into domain and name (if exists). */
+static errno_t update_all_filters(struct cache_tool_ctx *tctx,
+                                  struct sss_domain_info *dinfo)
+{
+    errno_t ret;
+
+    /* Update user filter */
+    ret = update_filter(tctx, dinfo, tctx->user_name,
+                        tctx->update_user_filter, "(%s=%s)",
+                        TYPE_USER, false,
+                        &tctx->user_filter);
+    if (ret != EOK) {
+        return ret;
+    }
+
+    /* Update group filter */
+    ret = update_filter(tctx, dinfo, tctx->group_name,
+                        tctx->update_group_filter, "(%s=%s)",
+                        TYPE_GROUP, false,
+                        &tctx->group_filter);
+    if (ret != EOK) {
+        return ret;
+    }
+
+    /* Update netgroup filter */
+    ret = update_filter(tctx, dinfo, tctx->netgroup_name,
+                        tctx->update_netgroup_filter, "(%s=%s)",
+                        TYPE_NETGROUP, false,
+                        &tctx->netgroup_filter);
+    if (ret != EOK) {
+        return ret;
+    }
+
+    /* Update service filter */
+    ret = update_filter(tctx, dinfo, tctx->service_name,
+                        tctx->update_service_filter, "(%s=%s)",
+                        TYPE_SERVICE, false,
+                        &tctx->service_filter);
+    if (ret != EOK) {
+        return ret;
+    }
+
+    /* Update autofs filter */
+    ret = update_filter(tctx, dinfo, tctx->autofs_name,
+                        tctx->update_autofs_filter,
+                        "(&(objectclass="SYSDB_AUTOFS_MAP_OC")(%s=%s))",
+                        TYPE_AUTOFSMAP, true,
+                        &tctx->autofs_filter);
+    if (ret != EOK) {
+        return ret;
+    }
+
+    /* Update ssh host filter */
+    ret = update_filter(tctx, dinfo, tctx->ssh_host_name,
+                        tctx->update_ssh_host_filter, "(%s=%s)",
+                        TYPE_SSH_HOST, false,
+                        &tctx->ssh_host_filter);
+    if (ret != EOK) {
+        return ret;
+    }
+
+    /* Update sudo rule filter */
+    ret = update_filter(tctx, dinfo, tctx->sudo_rule_name,
+                        tctx->update_sudo_rule_filter,
+                        "(%s=%s)", TYPE_SUDO_RULE, false,
+                        &tctx->sudo_rule_filter);
+    if (ret != EOK) {
+        return ret;
+    }
+
+    return EOK;
+}
+
+static errno_t invalidate_entry(TALLOC_CTX *ctx,
+                                struct sss_domain_info *domain,
+                                const char *name, int entry_type)
+{
+    struct sysdb_attrs *sys_attrs = NULL;
+    errno_t ret;
+
+    sys_attrs = sysdb_new_attrs(ctx);
+    if (sys_attrs) {
+        ret = sysdb_attrs_add_time_t(sys_attrs,
+                SYSDB_CACHE_EXPIRE, 1);
+        if (ret == EOK) {
+            switch (entry_type) {
+                case TYPE_USER:
+                    /* For users, we also need to reset the initgroups
+                     * cache expiry */
+                    ret = sysdb_attrs_add_time_t(sys_attrs,
+                            SYSDB_INITGR_EXPIRE, 1);
+                    if (ret != EOK) return ret;
+
+                    ret = sysdb_set_user_attr(domain, name, sys_attrs,
+                                              SYSDB_MOD_REP);
+                    if (ret != EOK) break;
+
+                    /* WARNING: Direct writing to persistent cache!! */
+                    ret = sysdb_invalidate_user_cache_entry(domain, name);
+                    break;
+                case TYPE_GROUP:
+                    ret = sysdb_set_group_attr(domain, name, sys_attrs,
+                                               SYSDB_MOD_REP);
+                    if (ret != EOK) break;
+
+                    /* WARNING: Direct writing to persistent cache!! */
+                    ret = sysdb_invalidate_group_cache_entry(domain, name);
+                    break;
+                case TYPE_NETGROUP:
+                    ret = sysdb_set_netgroup_attr(domain, name, sys_attrs,
+                                                  SYSDB_MOD_REP);
+                    break;
+                case TYPE_SERVICE:
+                    ret = sysdb_set_service_attr(domain, name,
+                                                 sys_attrs, SYSDB_MOD_REP);
+                    break;
+                case TYPE_AUTOFSMAP:
+                    ret = sysdb_set_autofsmap_attr(domain, name,
+                                                   sys_attrs, SYSDB_MOD_REP);
+                    break;
+                case TYPE_SSH_HOST:
+#ifdef BUILD_SSH
+                    ret = sysdb_set_ssh_host_attr(domain, name,
+                                                  sys_attrs, SYSDB_MOD_REP);
+#else  /* BUILD_SSH */
+                    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;
+            }
+            if (ret != EOK) {
+                DEBUG(SSSDBG_MINOR_FAILURE, "Could not set entry attributes\n");
+            }
+        } else {
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  "Could not add expiration time to attributes\n");
+        }
+        talloc_zfree(sys_attrs);
+    } else {
+        DEBUG(SSSDBG_MINOR_FAILURE, "Could not create sysdb attributes\n");
+        ret = ENOMEM;
+    }
+    return ret;
+}
+
+static bool invalidate_entries(TALLOC_CTX *ctx,
+                               struct sss_domain_info *dinfo,
+                               enum sss_cache_entry entry_type,
+                               const char *filter, const char *name)
+{
+    const char *attrs[] = {SYSDB_NAME, NULL};
+    size_t msg_count;
+    struct ldb_message **msgs;
+    const char *type_string = "unknown";
+    errno_t ret = EINVAL;
+    int i;
+    const char *c_name;
+    bool iret;
+
+    if (!filter) return false;
+    switch (entry_type) {
+    case TYPE_USER:
+        type_string = "user";
+        ret = sysdb_search_users(ctx, dinfo,
+                                 filter, attrs, &msg_count, &msgs);
+        break;
+    case TYPE_GROUP:
+        type_string = "group";
+        ret = sysdb_search_groups(ctx, dinfo,
+                                  filter, attrs, &msg_count, &msgs);
+        break;
+    case TYPE_NETGROUP:
+        type_string = "netgroup";
+        ret = sysdb_search_netgroups(ctx, dinfo,
+                                     filter, attrs, &msg_count, &msgs);
+        break;
+    case TYPE_SERVICE:
+        type_string = "service";
+        ret = sysdb_search_services(ctx, dinfo,
+                                    filter, attrs, &msg_count, &msgs);
+        break;
+    case TYPE_AUTOFSMAP:
+        type_string = "autofs map";
+        ret = search_autofsmaps(ctx, dinfo, filter, attrs, &msg_count, &msgs);
+        break;
+    case TYPE_SSH_HOST:
+        type_string = "ssh_host";
+#ifdef BUILD_SSH
+        ret = sysdb_search_ssh_hosts(ctx, dinfo,
+                                     filter, attrs, &msg_count, &msgs);
+#else  /* BUILD_SSH */
+        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) {
+        if (ret == ENOENT) {
+            DEBUG(SSSDBG_TRACE_FUNC, "'%s' %s: Not found in domain '%s'\n",
+                  type_string, name ? name : "", dinfo->name);
+        } else {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Searching for %s in domain %s with filter %s failed\n",
+                   type_string, dinfo->name, filter);
+        }
+        return false;
+    }
+
+    iret = true;
+    for (i = 0; i < msg_count; i++) {
+        c_name = ldb_msg_find_attr_as_string(msgs[i], SYSDB_NAME, NULL);
+        if (c_name == NULL) {
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  "Something bad happened, can't find attribute %s\n",
+                  SYSDB_NAME);
+            ERROR("Couldn't invalidate %1$s\n", type_string);
+            iret = false;
+        } else {
+            ret = invalidate_entry(ctx, dinfo, c_name, entry_type);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_MINOR_FAILURE,
+                      "Couldn't invalidate %s %s\n", type_string, c_name);
+                ERROR("Couldn't invalidate %1$s %2$s\n", type_string, c_name);
+                iret = false;
+            }
+        }
+    }
+    talloc_zfree(msgs);
+    return iret;
+}
+
+
+
+static errno_t init_domains(struct cache_tool_ctx *ctx,
+                            const char *domain)
+{
+    char *confdb_path;
+    int ret;
+    struct sss_domain_info *dinfo;
+
+    confdb_path = talloc_asprintf(ctx, "%s/%s", DB_PATH, CONFDB_FILE);
+    if (confdb_path == NULL) {
+        return ENOMEM;
+    }
+
+    /* Connect to the conf db */
+    ret = confdb_init(ctx, &ctx->confdb, confdb_path);
+    talloc_free(confdb_path);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Could not initialize connection to the confdb\n");
+        return ret;
+    }
+
+    if (domain) {
+        ret = sssd_domain_init(ctx, ctx->confdb,
+                               domain, DB_PATH, &ctx->domains);
+        if (ret != EOK) {
+            SYSDB_VERSION_ERROR(ret);
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Could not initialize connection to the sysdb\n");
+            return ret;
+        }
+
+    } else {
+        ret = confdb_get_domains(ctx->confdb, &ctx->domains);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "Could not initialize domains\n");
+            return ret;
+        }
+
+        ret = sysdb_init(ctx, ctx->domains);
+        SYSDB_VERSION_ERROR(ret);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Could not initialize connection to the sysdb\n");
+            return ret;
+        }
+    }
+
+    for (dinfo = ctx->domains; dinfo; dinfo = get_next_domain(dinfo, 0)) {
+        ret = sss_names_init(ctx, ctx->confdb, dinfo->name, &dinfo->names);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "sss_names_init() failed\n");
+            return ret;
+        }
+    }
+
+    return EOK;
+}
+
+static bool is_filter_valid(struct cache_tool_ctx *ctx,
+                            struct input_values *values, int idb)
+{
+    if ((idb & INVALIDATE_USERS) && ctx->user_filter == NULL) {
+        return false;
+    }
+
+    if ((idb & INVALIDATE_GROUPS) && ctx->group_filter == NULL) {
+        return false;
+    }
+
+    if ((idb & INVALIDATE_NETGROUPS) && ctx->netgroup_filter == NULL) {
+        return false;
+    }
+
+    if ((idb & INVALIDATE_SERVICES) && ctx->service_filter == NULL) {
+        return false;
+    }
+
+    if ((idb & INVALIDATE_AUTOFSMAPS) && ctx->autofs_filter == NULL) {
+        return false;
+    }
+
+    if ((idb & INVALIDATE_SSH_HOSTS) && ctx->ssh_host_filter == NULL) {
+        return false;
+    }
+
+    if (values->user && ctx->user_name == NULL) {
+        return false;
+    }
+
+    if (values->group && ctx->group_name == NULL) {
+        return false;
+    }
+
+    if (values->netgroup && ctx->netgroup_name == NULL) {
+        return false;
+    }
+
+    if (values->service && ctx->service_name == NULL) {
+        return false;
+    }
+
+    if (values->map && ctx->autofs_name == NULL) {
+        return false;
+    }
+
+    if (values->ssh_host && ctx->ssh_host_name == NULL) {
+        return false;
+    }
+
+    if (values->sudo_rule && ctx->sudo_rule_name == NULL) {
+        return false;
+    }
+
+    return true;
+}
+
+static errno_t init_context(int argc, const char *argv[],
+                            struct cache_tool_ctx **tctx)
+{
+    struct cache_tool_ctx *ctx = NULL;
+    int idb = INVALIDATE_NONE;
+    struct input_values values = { 0 };
+    int debug = SSSDBG_DEFAULT;
+    errno_t ret = EOK;
+
+    poptContext pc = NULL;
+    struct poptOption long_options[] = {
+        POPT_AUTOHELP
+        { "debug", '\0', POPT_ARG_INT | POPT_ARGFLAG_DOC_HIDDEN, &debug,
+            0, _("The debug level to run with"), NULL },
+        { "everything", 'E', POPT_ARG_NONE, NULL, 'e',
+            _("Invalidate all cached entries"), NULL },
+        { "user", 'u', POPT_ARG_STRING, &(values.user), 0,
+            _("Invalidate particular user"), NULL },
+        { "users", 'U', POPT_ARG_NONE, NULL, 'u',
+            _("Invalidate all users"), NULL },
+        { "group", 'g', POPT_ARG_STRING, &(values.group), 0,
+            _("Invalidate particular group"), NULL },
+        { "groups", 'G', POPT_ARG_NONE, NULL, 'g',
+            _("Invalidate all groups"), NULL },
+        { "netgroup", 'n', POPT_ARG_STRING, &(values.netgroup), 0,
+            _("Invalidate particular netgroup"), NULL },
+        { "netgroups", 'N', POPT_ARG_NONE, NULL, 'n',
+            _("Invalidate all netgroups"), NULL },
+        { "service", 's', POPT_ARG_STRING, &(values.service), 0,
+            _("Invalidate particular service"), NULL },
+        { "services", 'S', POPT_ARG_NONE, NULL, 's',
+            _("Invalidate all services"), NULL },
+#ifdef BUILD_AUTOFS
+        { "autofs-map", 'a', POPT_ARG_STRING, &(values.map), 0,
+            _("Invalidate particular autofs map"), NULL },
+        { "autofs-maps", 'A', POPT_ARG_NONE, NULL, 'a',
+            _("Invalidate all autofs maps"), NULL },
+#endif /* BUILD_AUTOFS */
+#ifdef BUILD_SSH
+        { "ssh-host", 'h', POPT_ARG_STRING, &(values.ssh_host), 0,
+            _("Invalidate particular SSH host"), NULL },
+        { "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, &(values.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, &(values.domain), 0,
+            _("Only invalidate entries from a particular domain"), NULL },
+        POPT_TABLEEND
+    };
+
+    ret = set_locale();
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "set_locale failed (%d): %s\n", ret, strerror(ret));
+        ERROR("Error setting the locale\n");
+        goto fini;
+    }
+
+    pc = poptGetContext(NULL, argc, argv, long_options, POPT_CONTEXT_KEEP_FIRST);
+    while ((ret = poptGetNextOpt(pc)) > 0) {
+        switch (ret) {
+            case 'u':
+                idb |= INVALIDATE_USERS;
+                break;
+            case 'g':
+                idb |= INVALIDATE_GROUPS;
+                break;
+            case 'n':
+                idb |= INVALIDATE_NETGROUPS;
+                break;
+            case 's':
+                idb |= INVALIDATE_SERVICES;
+                break;
+            case 'a':
+                idb |= INVALIDATE_AUTOFSMAPS;
+                break;
+            case 'h':
+                idb |= INVALIDATE_SSH_HOSTS;
+                break;
+            case 'r':
+                idb |= INVALIDATE_SUDO_RULES;
+                break;
+            case 'e':
+                idb = INVALIDATE_EVERYTHING;
+#ifdef BUILD_SUDO
+                idb |= INVALIDATE_SUDO_RULES;
+#endif /* BUILD_SUDO */
+                break;
+        }
+    }
+
+    DEBUG_CLI_INIT(debug);
+    debug_prg_name = argv[0];
+
+    if (ret != -1) {
+        BAD_POPT_PARAMS(pc, poptStrerror(ret), ret, fini);
+    }
+
+    if (poptGetArg(pc)) {
+        BAD_POPT_PARAMS(pc,
+                _("Unexpected argument(s) provided, options that "
+                  "invalidate a single object only accept a single "
+                  "provided argument.\n"),
+                  ret, fini);
+    }
+
+    if (idb == INVALIDATE_NONE && !values.user && !values.group &&
+        !values.netgroup && !values.service && !values.map &&
+        !values.ssh_host && !values.sudo_rule) {
+        BAD_POPT_PARAMS(pc,
+                _("Please select at least one object to invalidate\n"),
+                ret, fini);
+    }
+
+    CHECK_ROOT(ret, debug_prg_name);
+
+    ctx = talloc_zero(NULL, struct cache_tool_ctx);
+    if (ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Could not allocate memory for tools context\n");
+        ret = ENOMEM;
+        goto fini;
+    }
+
+    if (idb & INVALIDATE_USERS) {
+        ctx->user_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME);
+        ctx->update_user_filter = false;
+    } else if (values.user) {
+        ctx->user_name = talloc_strdup(ctx, values.user);
+        ctx->update_user_filter = true;
+    }
+
+    if (idb & INVALIDATE_GROUPS) {
+        ctx->group_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME);
+        ctx->update_group_filter = false;
+    } else if (values.group) {
+        ctx->group_name = talloc_strdup(ctx, values.group);
+        ctx->update_group_filter = true;
+    }
+
+    if (idb & INVALIDATE_NETGROUPS) {
+        ctx->netgroup_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME);
+        ctx->update_netgroup_filter = false;
+    } else if (values.netgroup) {
+        ctx->netgroup_name = talloc_strdup(ctx, values.netgroup);
+        ctx->update_netgroup_filter = true;
+    }
+
+    if (idb & INVALIDATE_SERVICES) {
+        ctx->service_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME);
+        ctx->update_service_filter = false;
+    } else if (values.service) {
+        ctx->service_name = talloc_strdup(ctx, values.service);
+        ctx->update_service_filter = true;
+    }
+
+    if (idb & INVALIDATE_AUTOFSMAPS) {
+        ctx->autofs_filter = talloc_asprintf(ctx, "(&(objectclass=%s)(%s=*))",
+                                             SYSDB_AUTOFS_MAP_OC, SYSDB_NAME);
+        ctx->update_autofs_filter = false;
+    } else if (values.map) {
+        ctx->autofs_name = talloc_strdup(ctx, values.map);
+        ctx->update_autofs_filter = true;
+    }
+
+    if (idb & INVALIDATE_SSH_HOSTS) {
+        ctx->ssh_host_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME);
+        ctx->update_ssh_host_filter = false;
+    } else if (values.ssh_host) {
+        ctx->ssh_host_name = talloc_strdup(ctx, values.ssh_host);
+        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 (values.sudo_rule) {
+        ctx->sudo_rule_name = talloc_strdup(ctx, values.sudo_rule);
+        ctx->update_sudo_rule_filter = true;
+    }
+
+    if (is_filter_valid(ctx, &values, idb) == false) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Construction of filters failed\n");
+        ret = ENOMEM;
+        goto fini;
+    }
+
+    ret = init_domains(ctx, values.domain);
+    if (ret != EOK) {
+        if (values.domain) {
+            ERROR("Could not open domain %1$s. If the domain is a subdomain "
+                  "(trusted domain), use fully qualified name instead of "
+                  "--domain/-d parameter.\n", values.domain);
+        } else {
+            ERROR("Could not open available domains\n");
+        }
+        DEBUG(SSSDBG_OP_FAILURE,
+              "Initialization of sysdb connections failed\n");
+        goto fini;
+    }
+
+    ret = EOK;
+
+fini:
+    poptFreeContext(pc);
+    free_input_values(&values);
+    if (ret != EOK && ctx) {
+        talloc_zfree(ctx);
+    }
+    if (ret == EOK) {
+        *tctx = ctx;
+    }
+    return ret;
+}
+
+
+
 static errno_t time_to_string(TALLOC_CTX *mem_ctx,
                               time_t timestamp,
                               const char **_value)
@@ -702,3 +1523,98 @@ errno_t sssctl_netgroup_show(struct sss_cmdline *cmdline,
 
     return EOK;
 }
+
+errno_t sssctl_expire_cache(struct sss_cmdline *cmdline,
+                            struct sss_tool_ctx *tool_ctx,
+                            void *pvt)
+{
+    errno_t ret;
+    struct cache_tool_ctx *tctx = NULL;
+    struct sysdb_ctx *sysdb;
+    bool skipped = true;
+    struct sss_domain_info *dinfo;
+
+    ret = init_context(cmdline->argc, cmdline->argv, &tctx);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Error initializing context for the application\n");
+        goto done;
+    }
+
+    for (dinfo = tctx->domains; dinfo;
+            dinfo = get_next_domain(dinfo, SSS_GND_DESCEND)) {
+        if (!IS_SUBDOMAIN(dinfo)) {
+            /* Update list of subdomains for this domain */
+            ret = sysdb_update_subdomains(dinfo, tctx->confdb);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_MINOR_FAILURE,
+                      "Failed to update subdomains for domain %s.\n", dinfo->name);
+            }
+        }
+
+        sysdb = dinfo->sysdb;
+        /* Update filters for each domain */
+        ret = update_all_filters(tctx, dinfo);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "Failed to update filters.\n");
+            goto done;
+        }
+
+        ret = sysdb_transaction_start(sysdb);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Could not start the transaction!\n");
+            goto done;
+        }
+
+        skipped &= !invalidate_entries(tctx, dinfo, TYPE_USER,
+                                       tctx->user_filter,
+                                       tctx->user_name);
+        skipped &= !invalidate_entries(tctx, dinfo, TYPE_GROUP,
+                                       tctx->group_filter,
+                                       tctx->group_name);
+        skipped &= !invalidate_entries(tctx, dinfo, TYPE_NETGROUP,
+                                       tctx->netgroup_filter,
+                                       tctx->netgroup_name);
+        skipped &= !invalidate_entries(tctx, dinfo, TYPE_SERVICE,
+                                       tctx->service_filter,
+                                       tctx->service_name);
+        skipped &= !invalidate_entries(tctx, dinfo, TYPE_AUTOFSMAP,
+                                       tctx->autofs_filter,
+                                       tctx->autofs_name);
+        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) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Could not commit the transaction!\n");
+            ret = sysdb_transaction_cancel(sysdb);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                      "Failed to cancel transaction\n");
+            }
+        }
+    }
+
+    if (skipped == true) {
+        ERROR("No cache object matched the specified search\n");
+        ret = ENOENT;
+        goto done;
+    } else {
+        ret = sss_memcache_clear_all();
+        if (ret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "Failed to clear memory cache.\n");
+            goto done;
+        }
+    }
+
+    ret = EOK;
+done:
+    if (tctx) talloc_free(tctx);
+    return ret;
+}

From e00a269f1f08234365941d9c8e4edd060e89a0b5 Mon Sep 17 00:00:00 2001
From: Justin Stephenson <[email protected]>
Date: Fri, 12 May 2017 22:42:40 -0400
Subject: [PATCH 3/4] SSSCTL: Add sss_debuglevel shell wrapper

The added sss_debuglevel shell wrapper will be used to replace
/usr/sbin/sss_debuglevel binary to merge sss_debuglevel into sssctl.
The wrapper will redirect sss_debuglevel to the sssctl debug-level
command performing the same task. The sss_debuglevel(8) man page is
updated to indicate that sss_debuglevel is deprecated and functionality
exists now in sssctl.

Resolves:
https://pagure.io/SSSD/sssd/issue/3057
---
 Makefile.am                     |  5 ++++-
 configure.ac                    |  1 +
 contrib/tools/sss_debuglevel.in |  4 ++++
 src/man/sss_debuglevel.8.xml    | 36 ++++--------------------------------
 4 files changed, 13 insertions(+), 33 deletions(-)
 create mode 100644 contrib/tools/sss_debuglevel.in

diff --git a/Makefile.am b/Makefile.am
index 73b3153..fe43a9b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -455,7 +455,10 @@ dist_noinst_SCRIPTS = \
     src/tests/krb5_proxy_check_test_data.conf \
     $(NULL)
 
-dist_sbin_SCRIPTS = contrib/tools/sss_cache
+dist_sbin_SCRIPTS = \
+    contrib/tools/sss_cache \
+    contrib/tools/sss_debuglevel \
+	$(NULL)
 
 dist_noinst_DATA = \
     src/config/testconfigs/sssd-valid.conf \
diff --git a/configure.ac b/configure.ac
index 1dfa2d2..1b2f88d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -505,5 +505,6 @@ AC_CONFIG_FILES([Makefile contrib/sssd.spec src/examples/rwtab src/doxy.config
                  src/config/setup.py
                  src/systemtap/sssd.stp
                  contrib/tools/sss_cache
+                 contrib/tools/sss_debuglevel
                  src/config/SSSDConfig/__init__.py])
 AC_OUTPUT
diff --git a/contrib/tools/sss_debuglevel.in b/contrib/tools/sss_debuglevel.in
new file mode 100644
index 0000000..8df4918
--- /dev/null
+++ b/contrib/tools/sss_debuglevel.in
@@ -0,0 +1,4 @@
+#!/bin/sh
+sbindir=@sbindir@
+echo "Redirecting to $sbindir/sssctl debug-level"
+$sbindir/sssctl debug-level $@
diff --git a/src/man/sss_debuglevel.8.xml b/src/man/sss_debuglevel.8.xml
index eb11540..0538dc5 100644
--- a/src/man/sss_debuglevel.8.xml
+++ b/src/man/sss_debuglevel.8.xml
@@ -13,7 +13,7 @@
 
     <refnamediv id='name'>
         <refname>sss_debuglevel</refname>
-        <refpurpose>change debug level while SSSD is running</refpurpose>
+        <refpurpose>[DEPRECATED] change debug level while SSSD is running</refpurpose>
     </refnamediv>
 
     <refsynopsisdiv id='synopsis'>
@@ -29,40 +29,12 @@
     <refsect1 id='description'>
         <title>DESCRIPTION</title>
         <para>
-            <command>sss_debuglevel</command> changes debug level of SSSD monitor
-            and providers to <replaceable>NEW_DEBUG_LEVEL</replaceable> while SSSD is running.
+            <command>sss_debuglevel</command> is deprecated and replaced
+            by the sssctl debug-level command. Please refer to the
+            <command>sssctl</command> man page for more information on sssctl usage.
         </para>
     </refsect1>
 
-    <refsect1 id='options'>
-        <title>OPTIONS</title>
-        <variablelist remap='IP'>
-            <varlistentry>
-                <term>
-                    <option>-c</option>,<option>--config</option>
-                </term>
-                <listitem>
-                    <para>
-                        Specify a non-default config file. The default is
-                        <filename>/etc/sssd/sssd.conf</filename>. For reference
-                        on the config file syntax and options, consult the
-                        <citerefentry>
-                            <refentrytitle>sssd.conf</refentrytitle>
-                            <manvolnum>5</manvolnum>
-                        </citerefentry>
-                        manual page.
-                    </para>
-                </listitem>
-            </varlistentry>
-            <varlistentry>
-                <term>
-                    <replaceable>NEW_DEBUG_LEVEL</replaceable>
-                </term>
-                <xi:include xmlns:xi="http://www.w3.org/2001/XInclude"; href="include/debug_levels.xml" />
-            </varlistentry>
-        </variablelist>
-    </refsect1>
-
     <xi:include xmlns:xi="http://www.w3.org/2001/XInclude"; href="include/seealso.xml" />
 
 </refentry>

From e70f52bdf71856165f32657f9f7de97a19f33d7e Mon Sep 17 00:00:00 2001
From: Justin Stephenson <[email protected]>
Date: Fri, 12 May 2017 23:10:18 -0400
Subject: [PATCH 4/4] SSSCTL: Move sss_debuglevel to sssctl debug-level

Move code from sss_debuglevel to sssctl_logs.c and add new debug-logs
sssctl command to perform the same task of changing debug level
dynamically.

POPT_CONTEXT_KEEP_FIRST Flag added to poptGetContext call in
sssctl_debug_level() to fix argument parsing.

Resolves:
https://pagure.io/SSSD/sssd/issue/3057
---
 Makefile.am                    |   1 -
 po/POTFILES.in                 |   1 -
 src/tools/sss_debuglevel.c     | 323 -----------------------------------------
 src/tools/sssctl/sssctl.c      |   1 +
 src/tools/sssctl/sssctl.h      |   4 +
 src/tools/sssctl/sssctl_logs.c | 293 +++++++++++++++++++++++++++++++++++++
 6 files changed, 298 insertions(+), 325 deletions(-)
 delete mode 100644 src/tools/sss_debuglevel.c

diff --git a/Makefile.am b/Makefile.am
index fe43a9b..97b0cc1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -141,7 +141,6 @@ sbin_PROGRAMS = \
     sss_usermod \
     sss_groupmod \
     sss_groupshow \
-    sss_debuglevel \
     sss_override \
     sss_seed \
     sssctl \
diff --git a/po/POTFILES.in b/po/POTFILES.in
index b928473..e11bbab 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -19,7 +19,6 @@ src/tools/sss_groupshow.c
 src/tools/sss_useradd.c
 src/tools/sss_userdel.c
 src/tools/sss_usermod.c
-src/tools/sss_debuglevel.c
 src/tools/tools_util.c
 src/tools/tools_util.h
 src/tools/sssctl/sssctl.c
diff --git a/src/tools/sss_debuglevel.c b/src/tools/sss_debuglevel.c
deleted file mode 100644
index e8b156e..0000000
--- a/src/tools/sss_debuglevel.c
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
-    Authors:
-        Pavel Březina <[email protected]>
-
-    Copyright (C) 2011 Red Hat
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 3 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <talloc.h>
-#include <popt.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <signal.h>
-#include <utime.h>
-#include <ldb.h>
-
-#include "config.h"
-#include "util/util.h"
-#include "tools/tools_util.h"
-#include "tools/common/sss_process.h"
-#include "confdb/confdb.h"
-
-#define CHECK(expr, done, msg) do { \
-    if (expr) { \
-        ERROR(msg "\n"); \
-        goto done; \
-    } \
-} while(0)
-
-struct debuglevel_tool_ctx {
-    struct confdb_ctx *confdb;
-    char **sections;
-};
-
-static errno_t set_debug_level(struct debuglevel_tool_ctx *tool_ctx,
-                               int debug_to_set, const char *config_file);
-static errno_t connect_to_confdb(TALLOC_CTX *ctx, struct confdb_ctx **cdb_ctx);
-static errno_t get_confdb_sections(TALLOC_CTX *ctx, struct confdb_ctx *confdb,
-                                   char ***output_sections);
-static int parse_debug_level(const char *strlevel);
-
-int main(int argc, const char **argv)
-{
-    int ret;
-    int pc_debug = SSSDBG_DEFAULT;
-    int debug_to_set = SSSDBG_INVALID;
-    const char *debug_as_string = NULL;
-    const char *config_file = NULL;
-    const char *pc_config_file = NULL;
-    struct debuglevel_tool_ctx *ctx = NULL;
-    struct poptOption long_options[] = {
-        POPT_AUTOHELP
-        {"debug", '\0', POPT_ARG_INT | POPT_ARGFLAG_DOC_HIDDEN, &pc_debug,
-            0, _("The debug level to run with"), NULL },
-        {"config", 'c', POPT_ARG_STRING, &pc_config_file,
-            0, _("Specify a non-default config file"), NULL},
-        POPT_TABLEEND
-    };
-    poptContext pc = NULL;
-
-    debug_prg_name = argv[0];
-
-    /* parse parameters */
-    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
-    poptSetOtherOptionHelp(pc, "DEBUG_LEVEL_TO_SET");
-    while((ret = poptGetNextOpt(pc)) != -1) {
-        switch(ret) {
-        default:
-            fprintf(stderr, "\nInvalid option %s: %s\n\n",
-                    poptBadOption(pc, 0), poptStrerror(ret));
-            poptPrintUsage(pc, stderr, 0);
-            ret = EXIT_FAILURE;
-            goto fini;
-        }
-    }
-    DEBUG_CLI_INIT(pc_debug);
-
-    /* get debug level */
-    debug_as_string = poptGetArg(pc);
-    if (debug_as_string == NULL) {
-        BAD_POPT_PARAMS(pc, _("Specify debug level you want to set\n"),
-                        ret, fini);
-    }
-
-    /* No more arguments expected. If something follows it is an error. */
-    if (poptGetArg(pc)) {
-        BAD_POPT_PARAMS(pc, _("Only one argument expected\n"),
-                        ret, fini);
-    }
-
-    /* get config file */
-    if (pc_config_file) {
-        config_file = talloc_strdup(ctx, pc_config_file);
-    } else {
-        config_file = talloc_strdup(ctx, SSSD_CONFIG_FILE);
-    }
-
-    if (config_file == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
-        ret = ENOMEM;
-        goto fini;
-    }
-
-    CHECK_ROOT(ret, debug_prg_name);
-
-    /* free pc_config_file? */
-    /* free debug_as_string? */
-
-    debug_to_set = parse_debug_level(debug_as_string);
-    CHECK(debug_to_set == SSSDBG_INVALID, fini, "Invalid debug level.");
-
-    /* allocate context */
-    ctx = talloc_zero(NULL, struct debuglevel_tool_ctx);
-    if (ctx == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "Could not allocate memory for tools context\n");
-        ret = ENOMEM;
-        goto fini;
-    }
-
-    ret = connect_to_confdb(ctx, &ctx->confdb);
-    CHECK(ret != EOK, fini, "Could not connect to configuration database.");
-
-    ret = get_confdb_sections(ctx, ctx->confdb, &ctx->sections);
-    CHECK(ret != EOK, fini, "Could not get all configuration sections.");
-
-    ret = set_debug_level(ctx, debug_to_set, config_file);
-    CHECK(ret != EOK, fini, "Could not set debug level.");
-
-    ret = sss_signal(SIGHUP);
-    CHECK(ret != EOK, fini,
-          "Could not force sssd processes to reload configuration. "
-          "Is sssd running?");
-
-fini:
-    poptFreeContext(pc);
-    talloc_free(ctx);
-    return ret;
-}
-
-errno_t set_debug_level(struct debuglevel_tool_ctx *tool_ctx,
-                        int debug_to_set, const char *config_file)
-{
-    int ret;
-    int err;
-    const char *values[2];
-    char **section = NULL;
-    TALLOC_CTX *tmp_ctx = talloc_new(NULL);
-
-    if (tmp_ctx == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
-        return ENOMEM;
-    }
-
-    /* convert debug_to_set to string */
-    values[0] = talloc_asprintf(tmp_ctx, "0x%.4x", debug_to_set);
-    if (values[0] == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Could not allocate memory for "
-              "debug_to_set to string conversion\n");
-        ret = ENOMEM;
-        goto done;
-    }
-    values[1] = NULL;
-
-    /* write to confdb */
-    for (section = tool_ctx->sections; *section != NULL; section++) {
-        ret = confdb_add_param(tool_ctx->confdb, 1, *section,
-                               CONFDB_SERVICE_DEBUG_LEVEL, values);
-        if (ret != EOK) {
-            goto done;
-        }
-    }
-
-    /*
-     * Change atime and mtime of sssd.conf,
-     * so the configuration can be restored on next start.
-     */
-    errno = 0;
-    if (utime(config_file, NULL) == -1 ) {
-        err = errno;
-        DEBUG(SSSDBG_MINOR_FAILURE, "Unable to change mtime of \"%s\": %s\n",
-              config_file, strerror(err));
-    }
-
-    ret = EOK;
-
-done:
-    talloc_free(tmp_ctx);
-    return ret;
-}
-
-errno_t connect_to_confdb(TALLOC_CTX *ctx, struct confdb_ctx **cdb_ctx)
-{
-    int ret;
-    char* confdb_path = NULL;
-
-    confdb_path = talloc_asprintf(ctx, "%s/%s", DB_PATH, CONFDB_FILE);
-    if (confdb_path == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "Could not allocate memory for confdb path\n");
-        return ENOMEM;
-    }
-
-    ret = confdb_init(ctx, cdb_ctx, confdb_path);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "Could not initialize connection to the confdb\n");
-    }
-
-    talloc_free(confdb_path);
-    return ret;
-}
-
-errno_t get_confdb_sections(TALLOC_CTX *ctx, struct confdb_ctx *confdb,
-                            char ***output_sections)
-{
-    int ret;
-    int domain_count = 0;
-    int i = 0;
-    struct sss_domain_info *domain = NULL;
-    struct sss_domain_info *domain_list = NULL;
-    char **sections;
-    const char *known_services[] = {
-        CONFDB_MONITOR_CONF_ENTRY,
-        CONFDB_NSS_CONF_ENTRY,
-        CONFDB_PAM_CONF_ENTRY,
-        CONFDB_PAC_CONF_ENTRY,
-        CONFDB_SSH_CONF_ENTRY,
-        CONFDB_SUDO_CONF_ENTRY,
-        CONFDB_AUTOFS_CONF_ENTRY,
-        CONFDB_IFP_CONF_ENTRY,
-    };
-    static const int known_services_count = sizeof(known_services)
-                                            / sizeof(*known_services);
-    TALLOC_CTX *tmp_ctx = talloc_new(NULL);
-
-    if (tmp_ctx == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
-        return ENOMEM;
-    }
-
-    /* get domains */
-    ret = confdb_get_domains(confdb, &domain_list);
-    if (ret != EOK)
-        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get domain list\n");
-
-    for (domain = domain_list;
-         domain;
-         domain = get_next_domain(domain, 0)) {
-        domain_count++;
-    }
-
-    /* allocate output space */
-    sections = talloc_array(ctx, char*,
-                            domain_count + known_services_count + 1);
-    if (sections == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "Could not allocate memory for sections\n");
-        ret = ENOMEM;
-        goto fail;
-    }
-
-    for (i = 0; i < known_services_count; i++) {
-        sections[i] = talloc_strdup(tmp_ctx, known_services[i]);
-        if (sections[i] == NULL) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
-            ret = ENOMEM;
-            goto fail;
-        }
-    }
-
-    for (domain = domain_list;
-         domain;
-         domain = get_next_domain(domain, 0), i++) {
-        sections[i] = talloc_asprintf(tmp_ctx, CONFDB_DOMAIN_PATH_TMPL,
-                                      domain->name);
-        if (sections[i] == NULL) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n");
-            ret = ENOMEM;
-            goto fail;
-        }
-    }
-
-    /* add NULL to the end */
-    sections[i] = NULL;
-
-    *output_sections = talloc_steal(ctx, sections);
-
-    return EOK;
-fail:
-    talloc_free(tmp_ctx);
-    return ret;
-}
-
-int parse_debug_level(const char *strlevel)
-{
-    long value;
-    char *endptr;
-
-    errno = 0;
-    value = strtol(strlevel, &endptr, 0);
-    if ((errno != 0) || (endptr == strlevel) || (*endptr != '\0')) {
-        return SSSDBG_INVALID;
-    }
-
-    return debug_convert_old_level(value);
-}
diff --git a/src/tools/sssctl/sssctl.c b/src/tools/sssctl/sssctl.c
index d0bf752..0f25414 100644
--- a/src/tools/sssctl/sssctl.c
+++ b/src/tools/sssctl/sssctl.c
@@ -277,6 +277,7 @@ int main(int argc, const char **argv)
         SSS_TOOL_DELIMITER("Log files tools:"),
         SSS_TOOL_COMMAND("logs-remove", "Remove existing SSSD log files", 0, sssctl_logs_remove),
         SSS_TOOL_COMMAND("logs-fetch", "Archive SSSD log files in tarball", 0, sssctl_logs_fetch),
+        SSS_TOOL_COMMAND("debug-level", "Change SSSD debug level", 0, sssctl_debug_level),
 #ifdef HAVE_LIBINI_CONFIG_V1_3
         SSS_TOOL_DELIMITER("Configuration files tools:"),
         SSS_TOOL_COMMAND_FLAGS("config-check", "Perform static analysis of SSSD configuration", 0, sssctl_config_check, SSS_TOOL_FLAG_SKIP_CMD_INIT),
diff --git a/src/tools/sssctl/sssctl.h b/src/tools/sssctl/sssctl.h
index dd7e039..f6f4b1a 100644
--- a/src/tools/sssctl/sssctl.h
+++ b/src/tools/sssctl/sssctl.h
@@ -106,6 +106,10 @@ errno_t sssctl_logs_fetch(struct sss_cmdline *cmdline,
                           struct sss_tool_ctx *tool_ctx,
                           void *pvt);
 
+errno_t sssctl_debug_level(struct sss_cmdline *cmdline,
+                          struct sss_tool_ctx *tool_ctx,
+                          void *pvt);
+
 errno_t sssctl_user_show(struct sss_cmdline *cmdline,
                          struct sss_tool_ctx *tool_ctx,
                          void *pvt);
diff --git a/src/tools/sssctl/sssctl_logs.c b/src/tools/sssctl/sssctl_logs.c
index 571207c..1a6a243 100644
--- a/src/tools/sssctl/sssctl_logs.c
+++ b/src/tools/sssctl/sssctl_logs.c
@@ -18,23 +18,214 @@
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <stdlib.h>
+#include <limits.h>
+#include <talloc.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <signal.h>
+#include <utime.h>
+#include <ldb.h>
 #include <popt.h>
 #include <stdio.h>
 
+#include "config.h"
 #include "util/util.h"
 #include "tools/common/sss_tools.h"
 #include "tools/common/sss_process.h"
 #include "tools/sssctl/sssctl.h"
 #include "tools/tools_util.h"
+#include "confdb/confdb.h"
 
 #define LOG_FILE(file) " " LOG_PATH "/" file
 #define LOG_FILES LOG_FILE("*.log")
 
+#define CHECK(expr, done, msg) do { \
+    if (expr) { \
+        ERROR(msg "\n"); \
+        goto done; \
+    } \
+} while(0)
+
+struct debuglevel_tool_ctx {
+    struct confdb_ctx *confdb;
+    char **sections;
+};
+
 struct sssctl_logs_opts {
     int delete;
     int archived;
 };
 
+errno_t set_debug_level(struct debuglevel_tool_ctx *tool_ctx,
+                        int debug_to_set, const char *config_file)
+{
+    int ret;
+    int err;
+    const char *values[2];
+    char **section = NULL;
+    TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+
+    if (tmp_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+        return ENOMEM;
+    }
+
+    /* convert debug_to_set to string */
+    values[0] = talloc_asprintf(tmp_ctx, "0x%.4x", debug_to_set);
+    if (values[0] == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Could not allocate memory for "
+              "debug_to_set to string conversion\n");
+        ret = ENOMEM;
+        goto done;
+    }
+    values[1] = NULL;
+
+    /* write to confdb */
+    for (section = tool_ctx->sections; *section != NULL; section++) {
+        ret = confdb_add_param(tool_ctx->confdb, 1, *section,
+                               CONFDB_SERVICE_DEBUG_LEVEL, values);
+        if (ret != EOK) {
+            goto done;
+        }
+    }
+
+    /*
+     * Change atime and mtime of sssd.conf,
+     * so the configuration can be restored on next start.
+     */
+    errno = 0;
+    if (utime(config_file, NULL) == -1 ) {
+        err = errno;
+        DEBUG(SSSDBG_MINOR_FAILURE, "Unable to change mtime of \"%s\": %s\n",
+              config_file, strerror(err));
+    }
+
+    ret = EOK;
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+errno_t connect_to_confdb(TALLOC_CTX *ctx, struct confdb_ctx **cdb_ctx)
+{
+    int ret;
+    char* confdb_path = NULL;
+
+    confdb_path = talloc_asprintf(ctx, "%s/%s", DB_PATH, CONFDB_FILE);
+    if (confdb_path == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Could not allocate memory for confdb path\n");
+        return ENOMEM;
+    }
+
+    ret = confdb_init(ctx, cdb_ctx, confdb_path);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Could not initialize connection to the confdb\n");
+    }
+
+    talloc_free(confdb_path);
+    return ret;
+}
+
+errno_t get_confdb_sections(TALLOC_CTX *ctx, struct confdb_ctx *confdb,
+                            char ***output_sections)
+{
+    int ret;
+    int domain_count = 0;
+    int i = 0;
+    struct sss_domain_info *domain = NULL;
+    struct sss_domain_info *domain_list = NULL;
+    char **sections;
+    const char *known_services[] = {
+        CONFDB_MONITOR_CONF_ENTRY,
+        CONFDB_NSS_CONF_ENTRY,
+        CONFDB_PAM_CONF_ENTRY,
+        CONFDB_PAC_CONF_ENTRY,
+        CONFDB_SSH_CONF_ENTRY,
+        CONFDB_SUDO_CONF_ENTRY,
+        CONFDB_AUTOFS_CONF_ENTRY,
+        CONFDB_IFP_CONF_ENTRY,
+    };
+    static const int known_services_count = sizeof(known_services)
+                                            / sizeof(*known_services);
+    TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+
+    if (tmp_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+        return ENOMEM;
+    }
+
+    /* get domains */
+    ret = confdb_get_domains(confdb, &domain_list);
+    if (ret != EOK)
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get domain list\n");
+
+    for (domain = domain_list;
+         domain;
+         domain = get_next_domain(domain, 0)) {
+        domain_count++;
+    }
+
+    /* allocate output space */
+    sections = talloc_array(ctx, char*,
+                            domain_count + known_services_count + 1);
+    if (sections == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Could not allocate memory for sections\n");
+        ret = ENOMEM;
+        goto fail;
+    }
+
+    for (i = 0; i < known_services_count; i++) {
+        sections[i] = talloc_strdup(tmp_ctx, known_services[i]);
+        if (sections[i] == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
+            ret = ENOMEM;
+            goto fail;
+        }
+    }
+
+    for (domain = domain_list;
+         domain;
+         domain = get_next_domain(domain, 0), i++) {
+        sections[i] = talloc_asprintf(tmp_ctx, CONFDB_DOMAIN_PATH_TMPL,
+                                      domain->name);
+        if (sections[i] == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n");
+            ret = ENOMEM;
+            goto fail;
+        }
+    }
+
+    /* add NULL to the end */
+    sections[i] = NULL;
+
+    *output_sections = talloc_steal(ctx, sections);
+
+    return EOK;
+fail:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+int parse_debug_level(const char *strlevel)
+{
+    long value;
+    char *endptr;
+
+    errno = 0;
+    value = strtol(strlevel, &endptr, 0);
+    if ((errno != 0) || (endptr == strlevel) || (*endptr != '\0')) {
+        return SSSDBG_INVALID;
+    }
+
+    return debug_convert_old_level(value);
+}
+
 errno_t sssctl_logs_remove(struct sss_cmdline *cmdline,
                            struct sss_tool_ctx *tool_ctx,
                            void *pvt)
@@ -105,3 +296,105 @@ errno_t sssctl_logs_fetch(struct sss_cmdline *cmdline,
 
     return EOK;
 }
+
+errno_t sssctl_debug_level(struct sss_cmdline *cmdline,
+                           struct sss_tool_ctx *tool_ctx,
+                           void *pvt)
+{
+    int ret;
+    int pc_debug = SSSDBG_DEFAULT;
+    int debug_to_set = SSSDBG_INVALID;
+    const char *debug_as_string = NULL;
+    const char *config_file = NULL;
+    const char *pc_config_file = NULL;
+    struct debuglevel_tool_ctx *ctx = NULL;
+    struct poptOption long_options[] = {
+        POPT_AUTOHELP
+        {"debug", '\0', POPT_ARG_INT | POPT_ARGFLAG_DOC_HIDDEN, &pc_debug,
+            0, _("The debug level to run with"), NULL },
+        {"config", 'c', POPT_ARG_STRING, &pc_config_file,
+            0, _("Specify a non-default config file"), NULL},
+        POPT_TABLEEND
+    };
+    poptContext pc = NULL;
+
+    debug_prg_name = cmdline->argv[0];
+
+    /* parse parameters */
+    pc = poptGetContext(cmdline->argv[0], cmdline->argc, cmdline->argv,
+                        long_options, POPT_CONTEXT_KEEP_FIRST);
+    poptSetOtherOptionHelp(pc, "DEBUG_LEVEL_TO_SET");
+    while((ret = poptGetNextOpt(pc)) != -1) {
+        switch(ret) {
+        default:
+            fprintf(stderr, "\nInvalid option %s: %s\n\n",
+                    poptBadOption(pc, 0), poptStrerror(ret));
+            poptPrintUsage(pc, stderr, 0);
+            ret = EXIT_FAILURE;
+            goto fini;
+        }
+    }
+    DEBUG_CLI_INIT(pc_debug);
+
+    /* get debug level */
+    debug_as_string = poptGetArg(pc);
+    if (debug_as_string == NULL) {
+        BAD_POPT_PARAMS(pc, _("Specify debug level you want to set\n"),
+                        ret, fini);
+    }
+
+    /* No more arguments expected. If something follows it is an error. */
+    if (poptGetArg(pc)) {
+        BAD_POPT_PARAMS(pc, _("Only one argument expected\n"),
+                        ret, fini);
+    }
+
+    /* get config file */
+    if (pc_config_file) {
+        config_file = talloc_strdup(ctx, pc_config_file);
+    } else {
+        config_file = talloc_strdup(ctx, SSSD_CONFIG_FILE);
+    }
+
+    if (config_file == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
+        ret = ENOMEM;
+        goto fini;
+    }
+
+    CHECK_ROOT(ret, debug_prg_name);
+
+    /* free pc_config_file? */
+    /* free debug_as_string? */
+
+    debug_to_set = parse_debug_level(debug_as_string);
+    CHECK(debug_to_set == SSSDBG_INVALID, fini, "Invalid debug level.");
+
+    /* allocate context */
+    ctx = talloc_zero(NULL, struct debuglevel_tool_ctx);
+    if (ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Could not allocate memory for tools context\n");
+        ret = ENOMEM;
+        goto fini;
+    }
+
+    ret = connect_to_confdb(ctx, &ctx->confdb);
+    CHECK(ret != EOK, fini, "Could not connect to configuration database.");
+
+    ret = get_confdb_sections(ctx, ctx->confdb, &ctx->sections);
+    CHECK(ret != EOK, fini, "Could not get all configuration sections.");
+
+    ret = set_debug_level(ctx, debug_to_set, config_file);
+    CHECK(ret != EOK, fini, "Could not set debug level.");
+
+    ret = sss_signal(SIGHUP);
+    CHECK(ret != EOK, fini,
+          "Could not force sssd processes to reload configuration. "
+          "Is sssd running?");
+
+fini:
+    poptFreeContext(pc);
+    talloc_free(ctx);
+    return ret;
+}
_______________________________________________
sssd-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to