On 04/12/2016 01:27 PM, Pavel Březina wrote:
On 04/06/2016 04:55 PM, Petr Cech wrote:
On 03/31/2016 03:29 PM, Pavel Březina wrote:
On 03/29/2016 03:17 PM, Petr Cech wrote:

Hi,

I am going to take three days of PTO. There is my work. Tests don't leak
and they really test :-) It is possible to use compact form of them,
maybe more help functions... But I hope that main idea is visible.

Pavel, you can see TODO comment on line 666. It is a bug. I think that
only one rule pass but they all failed. If you see the reason please
write me.

Z in the end of the format means UTC+0 timezone and localtime returns tm
relative to timezone on your machine. Thus you pass UTC+1 but evaluate
it as UTC+0 and you end up in future time. I think you should be fine if
you use gmtime instead.

Hi,

fixed patch set attached.

I changed schema from Z to +-0000 (by real localtime). It is still little wired. So I changed period from 1000 to 10000. It is hack, I know.

I will try to find out if there is bug in sysdb_sudo_convert_time().

And I changed order of includes in Makefile, but I didn't test it on debian. This was discuss offline.

Regards

--
Petr^4 Čech
>From 3dfb012c204fe700990d8f50e490b5b8168e9a82 Mon Sep 17 00:00:00 2001
From: Petr Cech <pc...@redhat.com>
Date: Wed, 24 Feb 2016 09:12:41 -0500
Subject: [PATCH 1/4] SYSDB: Add new funtions into sysdb_sudo

This patch adds two new functions into public
API of sysdb_sudo:
* sysdb_search_sudo_rules
* sysdb_set_sudo_rule_attr

Resolves:
https://fedorahosted.org/sssd/ticket/2081
---
 src/db/sysdb_sudo.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/db/sysdb_sudo.h | 15 +++++++++
 2 files changed, 112 insertions(+)

diff --git a/src/db/sysdb_sudo.c b/src/db/sysdb_sudo.c
index 76116abacb20219f0c1dcdde755e8268e10fd293..580f93ddd94d39ae992939bc556c2e2e5fe1649b 100644
--- a/src/db/sysdb_sudo.c
+++ b/src/db/sysdb_sudo.c
@@ -889,3 +889,100 @@ done:
 
     return ret;
 }
+
+errno_t sysdb_search_sudo_rules(TALLOC_CTX *mem_ctx,
+                                struct sss_domain_info *domain,
+                                const char *sub_filter,
+                                const char **attrs,
+                                size_t *_msgs_count,
+                                struct ldb_message ***_msgs)
+{
+    TALLOC_CTX *tmp_ctx;
+    size_t msgs_count;
+    struct ldb_message **msgs;
+    struct ldb_dn *dn;
+    char *filter;
+    int ret;
+
+    tmp_ctx = talloc_new(NULL);
+    NULL_CHECK(tmp_ctx, ret, done);
+
+    dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb, SYSDB_TMPL_CUSTOM_SUBTREE,
+                        SUDORULE_SUBDIR, domain->name);
+    if (dn == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "Failed to build base dn\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
+    if (sub_filter == NULL) {
+        filter = talloc_asprintf(tmp_ctx, "(%s)", SUDO_ALL_FILTER);
+    } else {
+        filter = talloc_asprintf(tmp_ctx, "(&%s%s)",
+                                 SUDO_ALL_FILTER, sub_filter);
+    }
+    if (filter == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "Failed to build filter\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
+    DEBUG(SSSDBG_TRACE_INTERNAL,
+          "Search sudo rules with filter: %s\n", filter);
+
+    ret = sysdb_search_entry(tmp_ctx, domain->sysdb, dn,
+                             LDB_SCOPE_SUBTREE, filter, attrs,
+                             &msgs_count, &msgs);
+
+    if (ret == ENOENT) {
+        DEBUG(SSSDBG_TRACE_INTERNAL, "No such entry\n");
+        *_msgs = NULL;
+        *_msgs_count = 0;
+        goto done;
+    } else if (ret != EOK) {
+        DEBUG(SSSDBG_MINOR_FAILURE, "Error: %d (%s)\n", ret, sss_strerror(ret));
+        goto done;
+    }
+
+    *_msgs_count = msgs_count;
+    *_msgs = talloc_steal(mem_ctx, msgs);
+
+    ret = EOK;
+
+done:
+    talloc_zfree(tmp_ctx);
+    return ret;
+}
+
+static struct ldb_dn *
+sysdb_sudo_rule_dn(TALLOC_CTX *mem_ctx,
+                   struct sss_domain_info *domain,
+                   const char *name)
+{
+    return sysdb_custom_dn(mem_ctx, domain, name, SUDORULE_SUBDIR);
+}
+
+errno_t
+sysdb_set_sudo_rule_attr(struct sss_domain_info *domain,
+                         const char *name,
+                         struct sysdb_attrs *attrs,
+                         int mod_op)
+{
+    errno_t ret;
+    struct ldb_dn *dn;
+    TALLOC_CTX *tmp_ctx;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        return ENOMEM;
+    }
+
+    dn = sysdb_sudo_rule_dn(tmp_ctx, domain, name);
+    NULL_CHECK(dn, ret, done);
+
+    ret = sysdb_set_entry_attr(domain->sysdb, dn, attrs, mod_op);
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
\ No newline at end of file
diff --git a/src/db/sysdb_sudo.h b/src/db/sysdb_sudo.h
index 515f45ab8b8f51cf7b1d27c1ba28ed8182bce6c0..7ada58b7393e295bdf7277a9aea60010c38aee6b 100644
--- a/src/db/sysdb_sudo.h
+++ b/src/db/sysdb_sudo.h
@@ -122,4 +122,19 @@ sysdb_sudo_store(struct sss_domain_info *domain,
                  struct sysdb_attrs **rules,
                  size_t num_rules);
 
+
+errno_t
+sysdb_search_sudo_rules(TALLOC_CTX *mem_ctx,
+                        struct sss_domain_info *domain,
+                        const char *sub_filter,
+                        const char **attrs,
+                        size_t *_msgs_count,
+                        struct ldb_message ***_msgs);
+
+errno_t
+sysdb_set_sudo_rule_attr(struct sss_domain_info *domain,
+                         const char *name,
+                         struct sysdb_attrs *attrs,
+                         int mod_op);
+
 #endif /* _SYSDB_SUDO_H_ */
-- 
2.5.5

>From 43ef6850f00aec08b586a96cb4fce575cc3d4697 Mon Sep 17 00:00:00 2001
From: Petr Cech <pc...@redhat.com>
Date: Thu, 25 Feb 2016 03:28:13 -0500
Subject: [PATCH 2/4] TESTS: Test of sysdb_search_sudo_rules

There are tests functions of sysdb_sudo_rules.

Resolves:
https://fedorahosted.org/sssd/ticket/2081
---
 Makefile.am                        |  18 +
 src/tests/cmocka/test_sysdb_sudo.c | 768 +++++++++++++++++++++++++++++++++++++
 2 files changed, 786 insertions(+)
 create mode 100644 src/tests/cmocka/test_sysdb_sudo.c

diff --git a/Makefile.am b/Makefile.am
index 8d2f588f4b71671bd257da48c817e9a3c7d0c147..ef0136667d583e2c76ae58a27f897063a001f759 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -231,6 +231,7 @@ if HAVE_CMOCKA
         sdap-tests \
         test_sysdb_views \
         test_sysdb_subdomains \
+        test_sysdb_sudo \
         test_sysdb_utils \
         test_be_ptask \
         test_copy_ccache \
@@ -2374,6 +2375,23 @@ test_sysdb_subdomains_LDADD = \
     libsss_test_common.la \
     $(NULL)
 
+test_sysdb_sudo_SOURCES = \
+    src/tests/cmocka/test_sysdb_sudo.c \
+    src/db/sysdb_sudo.c \
+    src/util/debug.c \
+    $(NULL)
+test_sysdb_sudo_CFLAGS = \
+    $(AM_CFLAGS) \
+    $(NULL)
+test_sysdb_sudo_LDADD = \
+    $(CMOCKA_LIBS) \
+    $(LDB_LIBS) \
+    $(TALLOC_LIBS) \
+    $(SSSD_INTERNAL_LTLIBS) \
+    $(POPT_LIBS) \
+    libsss_test_common.la \
+    $(NULL)
+
 test_sysdb_utils_SOURCES = \
     src/tests/cmocka/test_sysdb_utils.c \
     $(NULL)
diff --git a/src/tests/cmocka/test_sysdb_sudo.c b/src/tests/cmocka/test_sysdb_sudo.c
new file mode 100644
index 0000000000000000000000000000000000000000..18b2b58310bc7428b43413b1b07c02014ac13989
--- /dev/null
+++ b/src/tests/cmocka/test_sysdb_sudo.c
@@ -0,0 +1,768 @@
+/*
+    Authors:
+        Petr Čech <pc...@redhat.com>
+
+    Copyright (C) 2016 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 <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <popt.h>
+
+#include "tests/cmocka/common_mock.h"
+#include "src/db/sysdb_sudo.h"
+
+#define TESTS_PATH "tp_" BASE_FILE_STEM
+#define TEST_CONF_DB "test_sysdb_sudorules.ldb"
+#define TEST_DOM_NAME "test_domain.test"
+
+#define TEST_CACHE_SUDO_TIMEOUT "20"
+
+#define TEST_USER_NON_EXIST "no_user"
+
+#define TEST_GROUP_NAME "test_sudo_group"
+#define TEST_GID 10001
+
+struct test_user {
+    const char *name;
+    uid_t uid;
+    gid_t gid;
+} users[] = {{"test_user1", 1001, 1001},
+             {"test_user2", 1002, 1002},
+             {"test_user3", 1003, 1003}};
+
+struct test_rule {
+    const char *name;
+    const char *host;
+    const char *as_user;
+} rules[] = {{"test_rule1", "test_host1.test_domain.test", "root"},
+             {"test_rule2", "test_host2.test_domain.test", "root"},
+             {"test_rule3", "test_host3.test_domain.test", "root"}};
+
+struct sysdb_test_ctx {
+    struct sss_test_ctx *tctx;
+};
+
+static void create_groups(struct sss_domain_info *domain)
+{
+    errno_t ret;
+
+    ret = sysdb_add_group(domain, TEST_GROUP_NAME, TEST_GID,
+                          NULL, 30, time(NULL));
+    assert_int_equal(ret, EOK);
+}
+
+static void create_users(struct sss_domain_info *domain)
+{
+    errno_t ret;
+    int gid;
+
+    for (int i=0; i < 3; i++) {
+        gid = (i == 0) ? 0 : TEST_GID;
+        ret = sysdb_add_user(domain, users[i].name, users[i].uid, gid,
+                             users[i].name, NULL, "/bin/bash", domain->name,
+                             NULL, 30, time(NULL));
+        assert_int_equal(ret, EOK);
+    }
+}
+
+static void create_rule_attrs(struct sysdb_attrs *rule, int i)
+{
+    errno_t ret;
+
+    ret = sysdb_attrs_add_string_safe(rule, SYSDB_SUDO_CACHE_AT_CN,
+                                      rules[i].name);
+    assert_int_equal(ret, EOK);
+
+    ret = sysdb_attrs_add_string_safe(rule, SYSDB_SUDO_CACHE_AT_HOST,
+                                      rules[i].host);
+    assert_int_equal(ret, EOK);
+
+    ret = sysdb_attrs_add_string_safe(rule, SYSDB_SUDO_CACHE_AT_RUNASUSER,
+                                      rules[i].as_user);
+    assert_int_equal(ret, EOK);
+
+    ret = sysdb_attrs_add_string_safe(rule, SYSDB_SUDO_CACHE_AT_USER,
+                                      users[i].name);
+    assert_int_equal(ret, EOK);
+}
+
+static int get_stored_rules_count(struct sysdb_test_ctx *test_ctx)
+{
+    errno_t ret;
+    const char *attrs[] = {SYSDB_SUDO_CACHE_AT_CN, NULL};
+    struct ldb_message **msgs = NULL;
+    size_t msgs_count;
+
+    ret = sysdb_search_sudo_rules(test_ctx, test_ctx->tctx->dom,
+                                  "(objectClass=sudoRule)",
+                                  attrs, &msgs_count, &msgs);
+    if (!(ret == EOK || ret == ENOENT)) {
+        msgs_count = -1;
+    }
+    talloc_zfree(msgs);
+
+    return msgs_count;
+}
+
+static int test_sysdb_setup(void **state)
+{
+    struct sysdb_test_ctx *test_ctx;
+
+    assert_true(leak_check_setup());
+
+    test_ctx = talloc_zero(global_talloc_context, struct sysdb_test_ctx);
+    assert_non_null(test_ctx);
+
+    test_dom_suite_setup(TESTS_PATH);
+
+    test_ctx->tctx = create_dom_test_ctx(test_ctx, TESTS_PATH, TEST_CONF_DB,
+                                         TEST_DOM_NAME, "ipa", NULL);
+    assert_non_null(test_ctx->tctx);
+
+    create_groups(test_ctx->tctx->dom);
+    create_users(test_ctx->tctx->dom);
+
+    check_leaks_push(test_ctx);
+
+    *state = (void *) test_ctx;
+    return 0;
+}
+
+static int test_sysdb_teardown(void **state)
+{
+    struct sysdb_test_ctx *test_ctx;
+
+    test_ctx = talloc_get_type_abort(*state, struct sysdb_test_ctx);
+
+    test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME);
+
+    assert_true(check_leaks_pop(test_ctx));
+    talloc_zfree(test_ctx);
+    assert_true(leak_check_teardown());
+
+    return 0;
+}
+
+void test_store_sudo(void **state)
+{
+    errno_t ret;
+    char *filter;
+    int uid = 0;
+    char **groupnames = NULL;
+    const char *attrs[] = {SYSDB_SUDO_CACHE_AT_CN, SYSDB_SUDO_CACHE_AT_HOST,
+                           SYSDB_SUDO_CACHE_AT_RUNASUSER,
+                           SYSDB_SUDO_CACHE_AT_USER, NULL};
+    struct ldb_message **msgs = NULL;
+    size_t msgs_count;
+    const char *result;
+    struct sysdb_attrs *rule;
+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+                                                         struct sysdb_test_ctx);
+
+    rule = sysdb_new_attrs(test_ctx);
+    assert_non_null(rule);
+    create_rule_attrs(rule, 0);
+
+    ret = sysdb_sudo_store(test_ctx->tctx->dom, &rule, 1);
+    assert_int_equal(ret, EOK);
+
+    ret = sysdb_get_sudo_filter(test_ctx, users[0].name,
+                                uid, groupnames, SYSDB_SUDO_FILTER_USERNAME,
+                                &filter);
+    assert_int_equal(ret, EOK);
+
+    ret = sysdb_search_sudo_rules(test_ctx, test_ctx->tctx->dom, filter,
+                                  attrs, &msgs_count, &msgs);
+    assert_int_equal(ret, EOK);
+
+    assert_int_equal(msgs_count, 1);
+
+    result = ldb_msg_find_attr_as_string(msgs[0], SYSDB_SUDO_CACHE_AT_CN, NULL);
+    assert_non_null(result);
+    assert_string_equal(result, rules[0].name);
+
+    result = ldb_msg_find_attr_as_string(msgs[0], SYSDB_SUDO_CACHE_AT_HOST,
+                                         NULL);
+    assert_non_null(result);
+    assert_string_equal(result, rules[0].host);
+
+    result = ldb_msg_find_attr_as_string(msgs[0], SYSDB_SUDO_CACHE_AT_RUNASUSER,
+                                         NULL);
+    assert_non_null(result);
+    assert_string_equal(result, rules[0].as_user);
+
+    result = ldb_msg_find_attr_as_string(msgs[0], SYSDB_SUDO_CACHE_AT_USER,
+                                         NULL);
+    assert_non_null(result);
+    assert_string_equal(result, users[0].name);
+
+    talloc_zfree(rule);
+    talloc_zfree(filter);
+    talloc_zfree(msgs);
+}
+
+void test_sudo_purge_by_filter(void **state)
+{
+    errno_t ret;
+    struct sysdb_attrs *rule;
+    char *delete_filter;
+    int uid = 0;
+    char **groupnames = NULL;
+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+                                                         struct sysdb_test_ctx);
+
+    rule = sysdb_new_attrs(test_ctx);
+    assert_non_null(rule);
+    create_rule_attrs(rule, 0);
+
+    ret = sysdb_sudo_store(test_ctx->tctx->dom, &rule, 1);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(get_stored_rules_count(test_ctx), 1);
+
+    ret = sysdb_get_sudo_filter(test_ctx, users[0].name,
+                                uid, groupnames, SYSDB_SUDO_FILTER_USERNAME,
+                                &delete_filter);
+    assert_int_equal(ret, EOK);
+    assert_string_equal(delete_filter,
+                        "(&(objectClass=sudoRule)(|(sudoUser=test_user1)))");
+
+    ret = sysdb_sudo_purge(test_ctx->tctx->dom, delete_filter, NULL, 0);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(get_stored_rules_count(test_ctx), 0);
+
+    talloc_zfree(rule);
+    talloc_zfree(delete_filter);
+}
+
+void test_sudo_purge_by_rules(void **state)
+{
+    errno_t ret;
+    struct sysdb_attrs *rule;
+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+                                                         struct sysdb_test_ctx);
+
+    rule = sysdb_new_attrs(test_ctx);
+    assert_non_null(rule);
+    create_rule_attrs(rule, 0);
+
+    ret = sysdb_sudo_store(test_ctx->tctx->dom, &rule, 1);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(get_stored_rules_count(test_ctx), 1);
+
+    ret = sysdb_sudo_purge(test_ctx->tctx->dom, NULL, &rule, 1);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(get_stored_rules_count(test_ctx), 0);
+
+    talloc_zfree(rule);
+}
+
+void test_sudo_set_get_last_full_refresh(void **state)
+{
+    errno_t ret;
+    time_t now;
+    time_t loaded_time;
+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+                                                         struct sysdb_test_ctx);
+
+    now = time(NULL);
+    ret = sysdb_sudo_set_last_full_refresh(test_ctx->tctx->dom, now);
+    assert_int_equal(ret, EOK);
+
+    ret = sysdb_sudo_get_last_full_refresh(test_ctx->tctx->dom, &loaded_time);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(now, loaded_time);
+}
+
+void test_sudo_get_filter(void **state)
+{
+    errno_t ret;
+    char *filter;
+    int uid = 0;
+    char **groupnames = NULL;
+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+                                                         struct sysdb_test_ctx);
+
+    ret = sysdb_get_sudo_filter(test_ctx, users[0].name,
+                                uid, groupnames, SYSDB_SUDO_FILTER_USERNAME,
+                                &filter);
+    assert_int_equal(ret, EOK);
+    assert_string_equal(filter,
+                        "(&(objectClass=sudoRule)(|(sudoUser=test_user1)))");
+
+    talloc_zfree(filter);
+}
+
+void test_get_sudo_user_info(void **state)
+{
+    errno_t ret;
+    char **groupnames = NULL;
+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+                                                         struct sysdb_test_ctx);
+
+    /* User 1 has group. */
+    ret = sysdb_get_sudo_user_info(test_ctx, test_ctx->tctx->dom,
+                                   users[1].name, 0, &groupnames);
+    assert_int_equal(ret, EOK);
+    assert_string_equal(groupnames[0], TEST_GROUP_NAME);
+
+    talloc_zfree(groupnames);
+}
+
+void test_get_sudo_user_info_nogroup(void **state)
+{
+    errno_t ret;
+    char **groupnames = NULL;
+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+                                                         struct sysdb_test_ctx);
+
+    /* User 0 hasn't group. */
+    ret = sysdb_get_sudo_user_info(test_ctx, test_ctx->tctx->dom,
+                                   users[0].name, 0, &groupnames);
+    assert_int_equal(ret, EOK);
+    assert_null(groupnames);
+
+    talloc_zfree(groupnames);
+}
+
+void test_get_sudo_nouser(void **state)
+{
+    errno_t ret;
+    char **groupnames = NULL;
+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+                                                         struct sysdb_test_ctx);
+
+    ret = sysdb_get_sudo_user_info(test_ctx, test_ctx->tctx->dom,
+                                   TEST_USER_NON_EXIST, 0, &groupnames);
+    assert_int_equal(ret, ENOENT);
+}
+
+void test_set_sudo_rule_attr_add(void **state)
+{
+    errno_t ret;
+    struct sysdb_attrs *rule;
+    struct sysdb_attrs *new_rule;
+    const char *attrs[] = {SYSDB_SUDO_CACHE_AT_CN, SYSDB_SUDO_CACHE_AT_COMMAND,
+                           NULL};
+    char *filter;
+    int uid = 0;
+    char **groupnames = NULL;
+    struct ldb_message **msgs = NULL;
+    size_t msgs_count;
+    const char *result;
+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+                                                         struct sysdb_test_ctx);
+
+    rule = sysdb_new_attrs(test_ctx);
+    assert_non_null(rule);
+    create_rule_attrs(rule, 0);
+
+    ret = sysdb_sudo_store(test_ctx->tctx->dom, &rule, 1);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(get_stored_rules_count(test_ctx), 1);
+
+    new_rule = sysdb_new_attrs(test_ctx);
+    assert_non_null(new_rule);
+    ret = sysdb_attrs_add_string(new_rule, SYSDB_SUDO_CACHE_AT_COMMAND,
+                                 "test_command");
+    assert_int_equal(ret, EOK);
+
+    ret = sysdb_set_sudo_rule_attr(test_ctx->tctx->dom, rules[0].name,
+                                   new_rule, SYSDB_MOD_ADD);
+    assert_int_equal(ret, EOK);
+
+
+    ret = sysdb_get_sudo_filter(test_ctx, users[0].name,
+                                uid, groupnames, SYSDB_SUDO_FILTER_USERNAME,
+                                &filter);
+    assert_int_equal(ret, EOK);
+
+    ret = sysdb_search_sudo_rules(test_ctx, test_ctx->tctx->dom, filter,
+                                  attrs, &msgs_count, &msgs);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(msgs_count, 1);
+
+    result = ldb_msg_find_attr_as_string(msgs[0], SYSDB_SUDO_CACHE_AT_CN, NULL);
+    assert_non_null(result);
+    assert_string_equal(result, rules[0].name);
+
+    result = ldb_msg_find_attr_as_string(msgs[0], SYSDB_SUDO_CACHE_AT_COMMAND,
+                                         NULL);
+    assert_non_null(result);
+    assert_string_equal(result, "test_command");
+
+    talloc_zfree(rule);
+    talloc_zfree(new_rule);
+    talloc_zfree(filter);
+    talloc_zfree(msgs);
+}
+
+void test_set_sudo_rule_attr_replace(void **state)
+{
+    errno_t ret;
+    struct sysdb_attrs *rule;
+    struct sysdb_attrs *new_rule;
+    const char *attrs[] = {SYSDB_SUDO_CACHE_AT_CN, SYSDB_CACHE_EXPIRE, NULL};
+    char *filter;
+    int uid = 0;
+    char **groupnames = NULL;
+    struct ldb_message **msgs = NULL;
+    size_t msgs_count;
+    const char *result;
+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+                                                         struct sysdb_test_ctx);
+
+    rule = sysdb_new_attrs(test_ctx);
+    assert_non_null(rule);
+    create_rule_attrs(rule, 0);
+
+    ret = sysdb_sudo_store(test_ctx->tctx->dom, &rule, 1);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(get_stored_rules_count(test_ctx), 1);
+
+    new_rule = sysdb_new_attrs(test_ctx);
+    assert_non_null(new_rule);
+    ret = sysdb_attrs_add_time_t(new_rule, SYSDB_CACHE_EXPIRE, 10);
+    assert_int_equal(ret, EOK);
+
+    ret = sysdb_set_sudo_rule_attr(test_ctx->tctx->dom, rules[0].name,
+                                   new_rule, SYSDB_MOD_REP);
+    assert_int_equal(ret, EOK);
+
+
+    ret = sysdb_get_sudo_filter(test_ctx, users[0].name,
+                                uid, groupnames, SYSDB_SUDO_FILTER_USERNAME,
+                                &filter);
+    assert_int_equal(ret, EOK);
+
+    ret = sysdb_search_sudo_rules(test_ctx, test_ctx->tctx->dom, filter,
+                                  attrs, &msgs_count, &msgs);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(msgs_count, 1);
+
+    result = ldb_msg_find_attr_as_string(msgs[0], SYSDB_SUDO_CACHE_AT_CN, NULL);
+    assert_non_null(result);
+    assert_string_equal(result, rules[0].name);
+
+    result = ldb_msg_find_attr_as_string(msgs[0], SYSDB_CACHE_EXPIRE, NULL);
+    assert_non_null(result);
+    assert_string_equal(result, "10");
+
+    talloc_zfree(rule);
+    talloc_zfree(new_rule);
+    talloc_zfree(filter);
+    talloc_zfree(msgs);
+}
+
+void test_set_sudo_rule_attr_delete(void **state)
+{
+    errno_t ret;
+    struct sysdb_attrs *rule;
+    struct sysdb_attrs *new_rule;
+    const char *attrs[] = {SYSDB_SUDO_CACHE_AT_CN, SYSDB_SUDO_CACHE_AT_HOST,
+                           NULL};
+    char *filter;
+    int uid = 0;
+    char **groupnames = NULL;
+    struct ldb_message **msgs = NULL;
+    size_t msgs_count;
+    const char *result;
+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+                                                         struct sysdb_test_ctx);
+
+    rule = sysdb_new_attrs(test_ctx);
+    assert_non_null(rule);
+    create_rule_attrs(rule, 0);
+
+    ret = sysdb_sudo_store(test_ctx->tctx->dom, &rule, 1);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(get_stored_rules_count(test_ctx), 1);
+
+    new_rule = sysdb_new_attrs(test_ctx);
+    assert_non_null(new_rule);
+    ret = sysdb_attrs_add_string(new_rule, SYSDB_SUDO_CACHE_AT_HOST,
+                                 rules[0].host);
+    assert_int_equal(ret, EOK);
+
+    ret = sysdb_set_sudo_rule_attr(test_ctx->tctx->dom, rules[0].name,
+                                   new_rule, LDB_FLAG_MOD_DELETE);
+    assert_int_equal(ret, EOK);
+
+
+    ret = sysdb_get_sudo_filter(test_ctx, users[0].name,
+                                uid, groupnames, SYSDB_SUDO_FILTER_USERNAME,
+                                &filter);
+    assert_int_equal(ret, EOK);
+
+    ret = sysdb_search_sudo_rules(test_ctx, test_ctx->tctx->dom, filter,
+                                  attrs, &msgs_count, &msgs);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(msgs_count, 1);
+
+    result = ldb_msg_find_attr_as_string(msgs[0], SYSDB_SUDO_CACHE_AT_CN, NULL);
+    assert_non_null(result);
+    assert_string_equal(result, rules[0].name);
+
+    result = ldb_msg_find_attr_as_string(msgs[0], SYSDB_SUDO_CACHE_AT_HOST,
+                                         "deleted");
+    assert_non_null(result);
+    assert_string_equal(result, "deleted");
+
+    talloc_zfree(rule);
+    talloc_zfree(new_rule);
+    talloc_zfree(filter);
+    talloc_zfree(msgs);
+}
+
+void test_search_sudo_rules(void **state)
+{
+    errno_t ret;
+    char *filter;
+    const char *attrs[] = {SYSDB_NAME, NULL};
+    struct ldb_message **msgs = NULL;
+    size_t msgs_count;
+    size_t num_rules = 2;
+    struct sysdb_attrs *tmp_rules[num_rules];
+    const char *rule_names[num_rules];
+    const char *db_results[num_rules];
+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+                                                         struct sysdb_test_ctx);
+
+    tmp_rules[0] = sysdb_new_attrs(test_ctx);
+    assert_non_null(tmp_rules[0]);
+    create_rule_attrs(tmp_rules[0], 0);
+
+    tmp_rules[1] = sysdb_new_attrs(test_ctx);
+    assert_non_null(tmp_rules[1]);
+    create_rule_attrs(tmp_rules[1], 1);
+
+    ret = sysdb_sudo_store(test_ctx->tctx->dom, tmp_rules, 2);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(get_stored_rules_count(test_ctx), 2);
+
+    ret = sysdb_get_sudo_filter(test_ctx, NULL, 0, NULL,
+                                SYSDB_SUDO_FILTER_NONE, &filter);
+    assert_int_equal(ret, EOK);
+
+    ret = sysdb_search_sudo_rules(test_ctx, test_ctx->tctx->dom, filter,
+                                  attrs, &msgs_count, &msgs);
+    assert_int_equal(ret, EOK);
+
+    assert_int_equal(msgs_count, 2);
+
+    rule_names[0] = rules[0].name;
+    rule_names[1] = rules[1].name;
+
+    for (int i = 0; i < num_rules; ++i) {
+        db_results[i] = ldb_msg_find_attr_as_string(msgs[i], SYSDB_NAME, NULL);
+        assert_non_null(db_results[i]);
+    }
+
+    assert_string_not_equal(db_results[0], db_results[1]);
+    assert_true(are_values_in_array(rule_names, num_rules,
+                                    db_results, num_rules));
+
+    talloc_zfree(tmp_rules[0]);
+    talloc_zfree(tmp_rules[1]);
+    talloc_zfree(msgs);
+    talloc_zfree(filter);
+}
+
+void test_filter_rules_by_time(void **state)
+{
+    errno_t ret;
+    time_t cur_time;
+    struct sysdb_attrs *tmp_attr;
+    uint32_t _num_rules;
+    struct sysdb_attrs *tmp_rules[2];
+    struct sysdb_attrs **_rules;
+    struct sysdb_attrs **loaded_rules;
+    size_t msgs_count;
+    struct ldb_message **msgs = NULL;
+    char buff[20];
+    const char *attrs[] = {SYSDB_SUDO_CACHE_AT_CN, SYSDB_SUDO_CACHE_AT_HOST,
+                           SYSDB_SUDO_CACHE_AT_RUNASUSER,
+                           SYSDB_SUDO_CACHE_AT_USER,
+                           SYSDB_IPA_SUDORULE_NOTBEFORE,
+                           SYSDB_IPA_SUDORULE_NOTAFTER,NULL};
+    struct sysdb_test_ctx *test_ctx = talloc_get_type_abort(*state,
+                                                         struct sysdb_test_ctx);
+
+    tmp_rules[0] = sysdb_new_attrs(test_ctx);
+    assert_non_null(tmp_rules[0]);
+    create_rule_attrs(tmp_rules[0], 0);
+
+    tmp_rules[1] = sysdb_new_attrs(test_ctx);
+    assert_non_null(tmp_rules[1]);
+    create_rule_attrs(tmp_rules[1], 1);
+
+    ret = sysdb_sudo_store(test_ctx->tctx->dom, tmp_rules, 2);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(get_stored_rules_count(test_ctx), 2);
+
+    tmp_attr = sysdb_new_attrs(test_ctx);
+    assert_non_null(tmp_attr);
+    cur_time = time(NULL) + 10000;
+    strftime(buff, 20, "%Y%m%d%H%M%S%z", localtime(&cur_time));
+    ret = sysdb_attrs_add_string(tmp_attr, SYSDB_SUDO_CACHE_AT_NOTBEFORE, buff);
+    assert_int_equal(ret, EOK);
+    cur_time = time(NULL) + 20000;
+    strftime(buff, 20, "%Y%m%d%H%M%S%z", localtime(&cur_time));
+    ret = sysdb_attrs_add_string(tmp_attr, SYSDB_SUDO_CACHE_AT_NOTAFTER, buff);
+    assert_int_equal(ret, EOK);
+    ret = sysdb_set_sudo_rule_attr(test_ctx->tctx->dom, rules[0].name,
+                                   tmp_attr, SYSDB_MOD_ADD);
+    assert_int_equal(ret, EOK);
+    talloc_zfree(tmp_attr);
+
+    tmp_attr = sysdb_new_attrs(test_ctx);
+    assert_non_null(tmp_attr);
+    cur_time = time(NULL) - 10000;
+    strftime(buff, 20, "%Y%m%d%H%M%S%z", localtime(&cur_time));
+    ret = sysdb_attrs_add_string(tmp_attr, SYSDB_SUDO_CACHE_AT_NOTBEFORE, buff);
+    assert_int_equal(ret, EOK);
+    cur_time = time(NULL) + 10000;
+    strftime(buff, 20, "%Y%m%d%H%M%S%z", localtime(&cur_time));
+    ret = sysdb_attrs_add_string(tmp_attr, SYSDB_SUDO_CACHE_AT_NOTAFTER, buff);
+    assert_int_equal(ret, EOK);
+    ret = sysdb_set_sudo_rule_attr(test_ctx->tctx->dom, rules[1].name,
+                                   tmp_attr, SYSDB_MOD_ADD);
+    assert_int_equal(ret, EOK);
+    talloc_zfree(tmp_attr);
+
+    assert_int_equal(get_stored_rules_count(test_ctx), 2);
+
+    ret = sysdb_search_sudo_rules(test_ctx, test_ctx->tctx->dom,
+                                  "(objectClass=sudoRule)",
+                                  attrs, &msgs_count, &msgs);
+    assert_int_equal(ret, EOK);
+    assert_int_equal(msgs_count, 2);
+
+    ret = sysdb_msg2attrs(test_ctx, 2, msgs, &loaded_rules);
+    assert_int_equal(ret, EOK);
+
+    talloc_zfree(msgs);
+
+    ret =  sysdb_sudo_filter_rules_by_time(test_ctx, 2, loaded_rules, 0,
+                                           &_num_rules, &_rules);
+
+    assert_int_equal(ret, EOK);
+    assert_int_equal(_num_rules, 1);
+
+    talloc_zfree(tmp_rules[0]);
+    talloc_zfree(tmp_rules[1]);
+    talloc_zfree(loaded_rules);
+    talloc_zfree(_rules);
+}
+
+int main(int argc, const char *argv[])
+{
+    int rv;
+    poptContext pc;
+    int opt;
+    struct poptOption long_options[] = {
+        POPT_AUTOHELP
+        SSSD_DEBUG_OPTS
+        POPT_TABLEEND
+    };
+
+    const struct CMUnitTest tests[] = {
+        /* sysdb_sudo_store() */
+        cmocka_unit_test_setup_teardown(test_store_sudo,
+                                        test_sysdb_setup,
+                                        test_sysdb_teardown),
+
+        /* sysdb_sudo_purge() */
+        cmocka_unit_test_setup_teardown(test_sudo_purge_by_filter,
+                                        test_sysdb_setup,
+                                        test_sysdb_teardown),
+
+        cmocka_unit_test_setup_teardown(test_sudo_purge_by_rules,
+                                        test_sysdb_setup,
+                                        test_sysdb_teardown),
+
+        /*
+         * sysdb_sudo_set_last_full_refresh()
+         * sysdb_sudo_get_last_full_refresh()
+         */
+        cmocka_unit_test_setup_teardown(test_sudo_set_get_last_full_refresh,
+                                        test_sysdb_setup,
+                                        test_sysdb_teardown),
+
+        /* sysdb_get_sudo_filter() */
+        cmocka_unit_test_setup_teardown(test_sudo_get_filter,
+                                        test_sysdb_setup,
+                                        test_sysdb_teardown),
+
+        /* sysdb_get_sudo_user_info() */
+        cmocka_unit_test_setup_teardown(test_get_sudo_user_info,
+                                        test_sysdb_setup,
+                                        test_sysdb_teardown),
+        cmocka_unit_test_setup_teardown(test_get_sudo_user_info_nogroup,
+                                        test_sysdb_setup,
+                                        test_sysdb_teardown),
+
+        cmocka_unit_test_setup_teardown(test_get_sudo_nouser,
+                                        test_sysdb_setup,
+                                        test_sysdb_teardown),
+
+        /* sysdb_set_sudo_rule_attr() */
+        cmocka_unit_test_setup_teardown(test_set_sudo_rule_attr_add,
+                                        test_sysdb_setup,
+                                        test_sysdb_teardown),
+        cmocka_unit_test_setup_teardown(test_set_sudo_rule_attr_replace,
+                                        test_sysdb_setup,
+                                        test_sysdb_teardown),
+        cmocka_unit_test_setup_teardown(test_set_sudo_rule_attr_delete,
+                                        test_sysdb_setup,
+                                        test_sysdb_teardown),
+
+        /* sysdb_search_sudo_rules() */
+        cmocka_unit_test_setup_teardown(test_search_sudo_rules,
+                                        test_sysdb_setup,
+                                        test_sysdb_teardown),
+
+        /* sysdb_sudo_filter_rules_by_time() */
+        cmocka_unit_test_setup_teardown(test_filter_rules_by_time,
+                                        test_sysdb_setup,
+                                        test_sysdb_teardown),
+    };
+
+    /* Set debug level to invalid value so we can deside if -d 0 was used. */
+    debug_level = SSSDBG_INVALID;
+
+    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+    while((opt = poptGetNextOpt(pc)) != -1) {
+        switch(opt) {
+        default:
+            fprintf(stderr, "\nInvalid option %s: %s\n\n",
+                    poptBadOption(pc, 0), poptStrerror(opt));
+            poptPrintUsage(pc, stderr, 0);
+            return 1;
+        }
+    }
+    poptFreeContext(pc);
+
+    DEBUG_CLI_INIT(debug_level);
+
+    tests_set_cwd();
+    test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME);
+    rv = cmocka_run_group_tests(tests, NULL, NULL);
+
+    return rv;
+}
-- 
2.5.5

>From 52b8c112402483ca52c474eaaeca77085045b3c7 Mon Sep 17 00:00:00 2001
From: Petr Cech <pc...@redhat.com>
Date: Wed, 9 Mar 2016 11:30:35 -0500
Subject: [PATCH 3/4] SSS_CACHE: Refactor

Refactor of sss_cache tool.

Resolves:
https://fedorahosted.org/sssd/ticket/2081
---
 src/tools/sss_cache.c | 153 ++++++++++++++++++++++++++++++++++----------------
 1 file changed, 106 insertions(+), 47 deletions(-)

diff --git a/src/tools/sss_cache.c b/src/tools/sss_cache.c
index 88895e8de374ed3fe16cbc92125ee3b91172e39e..f64b200350721f2317b219681822fe1b33e077a7 100644
--- a/src/tools/sss_cache.c
+++ b/src/tools/sss_cache.c
@@ -75,6 +75,16 @@ static errno_t search_autofsmaps(TALLOC_CTX *mem_ctx,
                                  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 *user;
+};
+
 struct cache_tool_ctx {
     struct confdb_ctx *confdb;
     struct sss_domain_info *domains;
@@ -101,6 +111,9 @@ struct cache_tool_ctx {
     bool update_ssh_host_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);
 errno_t init_domains(struct cache_tool_ctx *ctx, const char *domain);
 errno_t init_context(int argc, const char *argv[], struct cache_tool_ctx **tctx);
 static errno_t invalidate_entry(TALLOC_CTX *ctx,
@@ -203,6 +216,17 @@ done:
     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->user);
+}
+
 static errno_t update_filter(struct cache_tool_ctx *tctx,
                              struct sss_domain_info *dinfo,
                              char *name, bool update, const char *fmt,
@@ -571,13 +595,7 @@ errno_t init_context(int argc, const char *argv[], struct cache_tool_ctx **tctx)
 {
     struct cache_tool_ctx *ctx = NULL;
     int idb = INVALIDATE_NONE;
-    char *user = NULL;
-    char *group = NULL;
-    char *netgroup = NULL;
-    char *service = NULL;
-    char *map = NULL;
-    char *ssh_host = NULL;
-    char *domain = NULL;
+    struct input_values values = {0};
     int debug = SSSDBG_DEFAULT;
     errno_t ret = EOK;
 
@@ -588,35 +606,35 @@ errno_t init_context(int argc, const char *argv[], struct cache_tool_ctx **tctx)
             0, _("The debug level to run with"), NULL },
         { "everything", 'E', POPT_ARG_NONE, NULL, 'e',
             _("Invalidate all cached entries except for sudo rules"), NULL },
-        { "user", 'u', POPT_ARG_STRING, &user, 0,
+        { "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, &group, 0,
+        { "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, &netgroup, 0,
+        { "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, &service, 0,
+        { "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, &map, 0,
+        { "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, &ssh_host, 0,
+        { "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 */
-        { "domain", 'd', POPT_ARG_STRING, &domain, 0,
+        { "domain", 'd', POPT_ARG_STRING, &(values.domain), 0,
             _("Only invalidate entries from a particular domain"), NULL },
         POPT_TABLEEND
     };
@@ -663,8 +681,9 @@ errno_t init_context(int argc, const char *argv[], struct cache_tool_ctx **tctx)
         BAD_POPT_PARAMS(pc, poptStrerror(ret), ret, fini);
     }
 
-    if (idb == INVALIDATE_NONE && !user && !group &&
-        !netgroup && !service && !map && !ssh_host) {
+    if (idb == INVALIDATE_NONE && !values.user && !values.group &&
+        !values.netgroup && !values.service && !values.map &&
+        !values.ssh_host) {
         BAD_POPT_PARAMS(pc,
                 _("Please select at least one object to invalidate\n"),
                 ret, fini);
@@ -683,32 +702,32 @@ errno_t init_context(int argc, const char *argv[], struct cache_tool_ctx **tctx)
     if (idb & INVALIDATE_USERS) {
         ctx->user_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME);
         ctx->update_user_filter = false;
-    } else if (user) {
-        ctx->user_name = talloc_strdup(ctx, user);
+    } 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 (group) {
-        ctx->group_name = talloc_strdup(ctx, group);
+    } 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 (netgroup) {
-        ctx->netgroup_name = talloc_strdup(ctx, netgroup);
+    } 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 (service) {
-        ctx->service_name = talloc_strdup(ctx, service);
+    } else if (values.service) {
+        ctx->service_name = talloc_strdup(ctx, values.service);
         ctx->update_service_filter = true;
     }
 
@@ -716,42 +735,31 @@ errno_t init_context(int argc, const char *argv[], struct cache_tool_ctx **tctx)
         ctx->autofs_filter = talloc_asprintf(ctx, "(&(objectclass=%s)(%s=*))",
                                              SYSDB_AUTOFS_MAP_OC, SYSDB_NAME);
         ctx->update_autofs_filter = false;
-    } else if (map) {
-        ctx->autofs_name = talloc_strdup(ctx, map);
+    } 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 (ssh_host) {
-        ctx->ssh_host_name = talloc_strdup(ctx, ssh_host);
+    } else if (values.ssh_host) {
+        ctx->ssh_host_name = talloc_strdup(ctx, values.ssh_host);
         ctx->update_ssh_host_filter = true;
     }
 
-    if (((idb & INVALIDATE_USERS) && !ctx->user_filter) ||
-        ((idb & INVALIDATE_GROUPS) && !ctx->group_filter) ||
-        ((idb & INVALIDATE_NETGROUPS) && !ctx->netgroup_filter) ||
-        ((idb & INVALIDATE_SERVICES) && !ctx->service_filter) ||
-        ((idb & INVALIDATE_AUTOFSMAPS) && !ctx->autofs_filter) ||
-        ((idb & INVALIDATE_SSH_HOSTS) && !ctx->ssh_host_filter) ||
-         (user && !ctx->user_name) ||
-         (group && !ctx->group_name) ||
-         (netgroup && !ctx->netgroup_name) ||
-         (service && !ctx->service_name) ||
-         (map && !ctx->autofs_name) ||
-         (ssh_host && !ctx->ssh_host_name)) {
+    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, domain);
+    ret = init_domains(ctx, values.domain);
     if (ret != EOK) {
-        if (domain) {
+        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", domain);
+                  "--domain/-d parameter.\n", values.domain);
         } else {
             ERROR("Could not open available domains\n");
         }
@@ -764,10 +772,7 @@ errno_t init_context(int argc, const char *argv[], struct cache_tool_ctx **tctx)
 
 fini:
     poptFreeContext(pc);
-    free(user);
-    free(group);
-    free(netgroup);
-    free(domain);
+    free_input_values(&values);
     if (ret != EOK && ctx) {
         talloc_zfree(ctx);
     }
@@ -777,6 +782,60 @@ fini:
     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;
+    }
+
+    return true;
+}
+
 static errno_t
 search_autofsmaps(TALLOC_CTX *mem_ctx,
                   struct sss_domain_info *domain,
-- 
2.5.5

>From c51b09d2361fbeecf224ac11a7c78bc8469bfd49 Mon Sep 17 00:00:00 2001
From: Petr Cech <pc...@redhat.com>
Date: Wed, 9 Mar 2016 11:33:22 -0500
Subject: [PATCH 4/4] TOOL: Invalidation of sudo rules at sss_cache

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

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

diff --git a/src/man/sss_cache.8.xml b/src/man/sss_cache.8.xml
index 1bc3633d9daa69ea59ba7ada0b6e180ece6e508a..81489288ced92ee5d4e7608ac092924369292bca 100644
--- a/src/man/sss_cache.8.xml
+++ b/src/man/sss_cache.8.xml
@@ -180,6 +180,29 @@
                     </para>
                 </listitem>
             </varlistentry>
+           <varlistentry condition="with_sudo">
+                <term>
+                    <option>-r</option>,<option>--sudo-rule</option>
+                    <replaceable>rule</replaceable>
+                </term>
+                <listitem>
+                    <para>
+                        Invalidate particular sudo rule.
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry condition="with_sudo">
+                <term>
+                    <option>-R</option>,<option>--sudo-rules</option>
+                </term>
+                <listitem>
+                    <para>
+                        Invalidate all cached sudo rules. This option
+                        overrides invalidation of specific sudo rule
+                        if it was also set.
+                    </para>
+                </listitem>
+            </varlistentry>
             <varlistentry>
                 <term>
                     <option>-d</option>,<option>--domain</option>
diff --git a/src/tools/sss_cache.c b/src/tools/sss_cache.c
index f64b200350721f2317b219681822fe1b33e077a7..569e33159fc52fc547d2e7189aac9bd97ae846bc 100644
--- a/src/tools/sss_cache.c
+++ b/src/tools/sss_cache.c
@@ -31,6 +31,7 @@
 #include "db/sysdb_services.h"
 #include "db/sysdb_autofs.h"
 #include "db/sysdb_ssh.h"
+#include "db/sysdb_sudo.h"
 
 #define INVALIDATE_NONE 0
 #define INVALIDATE_USERS 1
@@ -39,6 +40,7 @@
 #define INVALIDATE_SERVICES 8
 #define INVALIDATE_AUTOFSMAPS 16
 #define INVALIDATE_SSH_HOSTS 32
+#define INVALIDATE_SUDO_RULES 64
 
 #ifdef BUILD_AUTOFS
 #ifdef BUILD_SSH
@@ -67,7 +69,8 @@ enum sss_cache_entry {
     TYPE_NETGROUP,
     TYPE_SERVICE,
     TYPE_AUTOFSMAP,
-    TYPE_SSH_HOST
+    TYPE_SSH_HOST,
+    TYPE_SUDO_RULE
 };
 
 static errno_t search_autofsmaps(TALLOC_CTX *mem_ctx,
@@ -82,6 +85,7 @@ struct input_values {
     char *netgroup;
     char *service;
     char *ssh_host;
+    char *sudo_rule;
     char *user;
 };
 
@@ -95,6 +99,7 @@ struct cache_tool_ctx {
     char *service_filter;
     char *autofs_filter;
     char *ssh_host_filter;
+    char *sudo_rule_filter;
 
     char *user_name;
     char *group_name;
@@ -102,6 +107,7 @@ struct cache_tool_ctx {
     char *service_name;
     char *autofs_name;
     char *ssh_host_name;
+    char *sudo_rule_name;
 
     bool update_user_filter;
     bool update_group_filter;
@@ -109,6 +115,7 @@ struct cache_tool_ctx {
     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);
@@ -185,6 +192,9 @@ int main(int argc, const char *argv[])
         skipped &= !invalidate_entries(tctx, dinfo, TYPE_SSH_HOST,
                                        tctx->ssh_host_filter,
                                        tctx->ssh_host_name);
+        skipped &= !invalidate_entries(tctx, dinfo, TYPE_SUDO_RULE,
+                                       tctx->sudo_rule_filter,
+                                       tctx->sudo_rule_name);
 
         ret = sysdb_transaction_commit(sysdb);
         if (ret != EOK) {
@@ -224,6 +234,7 @@ static void free_input_values(struct input_values *values)
     free(values->netgroup);
     free(values->service);
     free(values->ssh_host);
+    free(values->sudo_rule);
     free(values->user);
 }
 
@@ -380,6 +391,14 @@ static errno_t update_all_filters(struct cache_tool_ctx *tctx,
         return ret;
     }
 
+    /* Update sudo rule filter */
+    ret = update_filter(tctx, dinfo, tctx->sudo_rule_name,
+                        tctx->update_sudo_rule_filter, "(%s=%s)", false,
+                        &tctx->sudo_rule_filter);
+    if (ret != EOK) {
+        return ret;
+    }
+
     return EOK;
 }
 
@@ -432,6 +451,15 @@ static bool invalidate_entries(TALLOC_CTX *ctx,
         ret = ENOSYS;
 #endif /* BUILD_SSH */
         break;
+    case TYPE_SUDO_RULE:
+        type_string = "sudo_rule";
+#ifdef BUILD_SUDO
+        ret = sysdb_search_sudo_rules(ctx, dinfo,
+                                      filter, attrs, &msg_count, &msgs);
+#else  /* BUILD_SUDO */
+        ret = ENOSYS;
+#endif /* BUILD_SUDO */
+        break;
     }
 
     if (ret != EOK) {
@@ -516,6 +544,14 @@ static errno_t invalidate_entry(TALLOC_CTX *ctx,
                     ret = ENOSYS;
 #endif /* BUILD_SSH */
                     break;
+                case TYPE_SUDO_RULE:
+#ifdef BUILD_SUDO
+                    ret = sysdb_set_sudo_rule_attr(domain, name,
+                                                   sys_attrs, SYSDB_MOD_REP);
+#else  /* BUILD_SUDO */
+                    ret = ENOSYS;
+#endif /* BUILD_SUDO */
+                    break;
                 default:
                     return EINVAL;
             }
@@ -605,7 +641,7 @@ errno_t init_context(int argc, const char *argv[], struct cache_tool_ctx **tctx)
         { "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 except for sudo rules"), NULL },
+            _("Invalidate all cached entries"), NULL },
         { "user", 'u', POPT_ARG_STRING, &(values.user), 0,
             _("Invalidate particular user"), NULL },
         { "users", 'U', POPT_ARG_NONE, NULL, 'u',
@@ -634,6 +670,12 @@ errno_t init_context(int argc, const char *argv[], struct cache_tool_ctx **tctx)
         { "ssh-hosts", 'H', POPT_ARG_NONE, NULL, 'h',
             _("Invalidate all SSH hosts"), NULL },
 #endif /* BUILD_SSH */
+#ifdef BUILD_SUDO
+        { "sudo-rule", 'r', POPT_ARG_STRING, &(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
@@ -668,8 +710,14 @@ errno_t init_context(int argc, const char *argv[], struct cache_tool_ctx **tctx)
             case 'h':
                 idb |= INVALIDATE_SSH_HOSTS;
                 break;
+            case 'r':
+                idb |= INVALIDATE_SUDO_RULES;
+                break;
             case 'e':
                 idb = INVALIDATE_EVERYTHING;
+#ifdef BUILD_SUDO
+                idb |= INVALIDATE_SUDO_RULES;
+#endif /* BUILD_SUDO */
                 break;
         }
     }
@@ -683,7 +731,7 @@ errno_t init_context(int argc, const char *argv[], struct cache_tool_ctx **tctx)
 
     if (idb == INVALIDATE_NONE && !values.user && !values.group &&
         !values.netgroup && !values.service && !values.map &&
-        !values.ssh_host) {
+        !values.ssh_host && !values.sudo_rule) {
         BAD_POPT_PARAMS(pc,
                 _("Please select at least one object to invalidate\n"),
                 ret, fini);
@@ -748,6 +796,14 @@ errno_t init_context(int argc, const char *argv[], struct cache_tool_ctx **tctx)
         ctx->update_ssh_host_filter = true;
     }
 
+    if (idb & INVALIDATE_SUDO_RULES) {
+        ctx->sudo_rule_filter = talloc_asprintf(ctx, "(%s=*)", SYSDB_NAME);
+        ctx->update_sudo_rule_filter = false;
+    } else if (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;
@@ -833,6 +889,10 @@ static bool is_filter_valid(struct cache_tool_ctx *ctx,
         return false;
     }
 
+    if (values->sudo_rule && ctx->sudo_rule_name == NULL) {
+        return false;
+    }
+
     return true;
 }
 
-- 
2.5.5

_______________________________________________
sssd-devel mailing list
sssd-devel@lists.fedorahosted.org
https://lists.fedorahosted.org/admin/lists/sssd-devel@lists.fedorahosted.org

Reply via email to