[SSSD] [PATCH] Improve negcache with subdomains

Jakub Hrozek jhrozek at redhat.com
Mon Mar 30 09:47:29 UTC 2015


Hi,

I noticed this bug while working on the SSH fix with
default_domain_suffix. It turns out our filter_users/filter_groups don't
work well in this scenario, which might have effect on the server load
even. Attached are patches that re-initialize negcache with filter_lists
contents after the subdomains are (re)discovered. All patches have
tests.
-------------- next part --------------
>From c00a8d74bfe74c3f00e29d1b5c0271bc1bfdb24a Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Fri, 27 Mar 2015 12:57:17 +0100
Subject: [PATCH 1/5] ncache: Fix sss_ncache_reset_permanent

There was an off-by-one error in sss_ncache_reset_permanent that
prevented the reset from working.
---
 src/responder/common/negcache.c  |  2 +-
 src/tests/cmocka/test_negcache.c | 11 +++++++++++
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c
index 88dd18fa5348fca223a0b2db844e3d17286045b7..04c9a53f556497173daf1ef9c562896cb2d5bbc9 100644
--- a/src/responder/common/negcache.c
+++ b/src/responder/common/negcache.c
@@ -556,7 +556,7 @@ static int delete_permanent(struct tdb_context *tdb,
     char *ep;
 
     if (strncmp((char *)key.dptr,
-                NC_ENTRY_PREFIX, sizeof(NC_ENTRY_PREFIX)) != 0) {
+                NC_ENTRY_PREFIX, sizeof(NC_ENTRY_PREFIX) - 1) != 0) {
         /* not interested in this key */
         return 0;
     }
diff --git a/src/tests/cmocka/test_negcache.c b/src/tests/cmocka/test_negcache.c
index f98081337517de2c4fba62910a032323f57ba259..4502c0294e772b15bf230d485e02c40e2ffbf2d6 100644
--- a/src/tests/cmocka/test_negcache.c
+++ b/src/tests/cmocka/test_negcache.c
@@ -563,10 +563,21 @@ static void test_sss_ncache_reset_permanent(void **state)
 {
     int ret;
     struct test_state *ts;
+    const bool permanent = true;
 
     ts = talloc_get_type_abort(*state, struct test_state);
+
+    ret = sss_ncache_set_uid(ts->ctx, permanent, 0);
+    assert_int_equal(ret, EOK);
+
+    ret = sss_ncache_check_uid(ts->ctx, 0, 0);
+    assert_int_equal(ret, EEXIST);
+
     ret = sss_ncache_reset_permanent(ts->ctx);
     assert_int_equal(ret, EOK);
+
+    ret = sss_ncache_check_uid(ts->ctx, 0, 0);
+    assert_int_equal(ret, ENOENT);
 }
 
 static void test_sss_ncache_prepopulate(void **state)
-- 
2.1.0

-------------- next part --------------
>From d2e30c6083b5082b90343ca6be10e1899f44d911 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Fri, 27 Mar 2015 12:30:53 +0100
Subject: [PATCH 2/5] ncache: Silence critical error from filter_users when
 default_domain_suffix is set

When default_domain_suffix is used and filter_users is set (at least
root is always, by default), SSSD tried to add the negcache entry to the
default domain. But since the default domain is not known after start
up, adding the entries fail with a verbose error message.

This patch handles EAGAIN returned from the parsing function while
setting negcache entries gracefully and also makes the debug message in
parsing function more precise.
---
 src/responder/common/negcache.c  | 18 +++++++++--
 src/tests/cmocka/test_negcache.c | 69 ++++++++++++++++++++++++++++++++++++++--
 src/util/usertools.c             |  3 +-
 3 files changed, 82 insertions(+), 8 deletions(-)

diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c
index 04c9a53f556497173daf1ef9c562896cb2d5bbc9..3e58c3e7f3888992069dc573ae458e0da641dc7b 100644
--- a/src/responder/common/negcache.c
+++ b/src/responder/common/negcache.c
@@ -630,7 +630,11 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache,
                                              rctx->default_domain,
                                              filter_list[i],
                                              &domainname, &name);
-            if (ret != EOK) {
+            if (ret == EAGAIN) {
+                DEBUG(SSSDBG_MINOR_FAILURE,
+                      "cannot add [%s] to negcache because the required or "
+                      "default domain are not known yet\n", filter_list[i]);
+            } else if (ret != EOK) {
                 DEBUG(SSSDBG_CRIT_FAILURE,
                       "Invalid name in filterUsers list: [%s] (%d)\n",
                          filter_list[i], ret);
@@ -679,7 +683,11 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache,
         ret = sss_parse_name_for_domains(tmpctx, domain_list,
                                          rctx->default_domain, filter_list[i],
                                          &domainname, &name);
-        if (ret != EOK) {
+        if (ret == EAGAIN) {
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  "Cannot add [%s] to negcache because the required or "
+                  "default domain are not known yet\n", filter_list[i]);
+        } else if (ret != EOK) {
             DEBUG(SSSDBG_CRIT_FAILURE,
                   "Invalid name in filterUsers list: [%s] (%d)\n",
                      filter_list[i], ret);
@@ -783,7 +791,11 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache,
         ret = sss_parse_name_for_domains(tmpctx, domain_list,
                                          rctx->default_domain, filter_list[i],
                                          &domainname, &name);
-        if (ret != EOK) {
+        if (ret == EAGAIN) {
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  "Cannot add [%s] to negcache because the required or "
+                  "default domain are not known yet\n", filter_list[i]);
+        } else if (ret != EOK) {
             DEBUG(SSSDBG_CRIT_FAILURE,
                   "Invalid name in filterGroups list: [%s] (%d)\n",
                      filter_list[i], ret);
diff --git a/src/tests/cmocka/test_negcache.c b/src/tests/cmocka/test_negcache.c
index 4502c0294e772b15bf230d485e02c40e2ffbf2d6..5ade3fd4b347a6c7c74754730bca4b82c71ddf06 100644
--- a/src/tests/cmocka/test_negcache.c
+++ b/src/tests/cmocka/test_negcache.c
@@ -590,8 +590,8 @@ static void test_sss_ncache_prepopulate(void **state)
     struct sss_domain_info *dom;
 
     struct sss_test_conf_param params[] = {
-        { "filter_users", "testuser1" },
-        { "filter_groups", "testgroup1" },
+        { "filter_users", "testuser1, testuser2@"TEST_DOM_NAME", testuser3 at somedomain" },
+        { "filter_groups", "testgroup1, testgroup2@"TEST_DOM_NAME", testgroup3 at somedomain" },
         { NULL, NULL },
     };
 
@@ -628,6 +628,67 @@ static void test_sss_ncache_prepopulate(void **state)
 
     ret = sss_ncache_check_group(ncache, 1, dom, "testgroup1");
     assert_int_equal(ret, EEXIST);
+
+    ret = sss_ncache_check_user(ncache, 1, dom, "testuser2");
+    assert_int_equal(ret, EEXIST);
+
+    ret = sss_ncache_check_group(ncache, 1, dom, "testgroup2");
+    assert_int_equal(ret, EEXIST);
+
+    ret = sss_ncache_check_user(ncache, 1, dom, "testuser3");
+    assert_int_equal(ret, ENOENT);
+
+    ret = sss_ncache_check_group(ncache, 1, dom, "testgroup3");
+    assert_int_equal(ret, ENOENT);
+
+    ret = sss_ncache_check_user(ncache, 1, dom, "testuser3 at somedomain");
+    assert_int_equal(ret, ENOENT);
+
+    ret = sss_ncache_check_group(ncache, 1, dom, "testgroup3 at somedomain");
+    assert_int_equal(ret, ENOENT);
+}
+
+static void test_sss_ncache_default_domain_suffix(void **state)
+{
+    int ret;
+    struct test_state *ts;
+    struct tevent_context *ev;
+    struct sss_nc_ctx *ncache;
+    struct sss_test_ctx *tc;
+    struct sss_domain_info *dom;
+
+    struct sss_test_conf_param params[] = {
+        { "filter_users", "testuser1, testuser2@"TEST_DOM_NAME", testuser3 at somedomain" },
+        { "filter_groups", "testgroup1, testgroup2@"TEST_DOM_NAME", testgroup3 at somedomain" },
+        { NULL, NULL },
+    };
+
+    ts = talloc_get_type_abort(*state, struct test_state);
+
+    ev = tevent_context_init(ts);
+    assert_non_null(ev);
+
+    dom = talloc_zero(ts, struct sss_domain_info);
+    assert_non_null(dom);
+    dom->name = discard_const_p(char, TEST_DOM_NAME);
+
+    ts->nctx = mock_nctx(ts);
+    assert_non_null(ts->nctx);
+
+    tc = create_dom_test_ctx(ts, TESTS_PATH, TEST_CONF_DB,
+                             TEST_DOM_NAME, TEST_ID_PROVIDER, params);
+    assert_non_null(tc);
+
+    ncache = ts->ctx;
+    ts->rctx = mock_rctx(ts, ev, dom, ts->nctx);
+    assert_non_null(ts->rctx);
+    ts->rctx->default_domain = discard_const(TEST_DOM_NAME);
+
+    ret = sss_names_init(ts, tc->confdb, TEST_DOM_NAME, &dom->names);
+    assert_int_equal(ret, EOK);
+
+    ret = sss_ncache_prepopulate(ncache, tc->confdb, ts->rctx);
+    assert_int_equal(ret, EOK);
 }
 
 int main(void)
@@ -648,7 +709,9 @@ int main(void)
         cmocka_unit_test_setup_teardown(test_sss_ncache_reset_permanent, setup,
                                         teardown),
         cmocka_unit_test_setup_teardown(test_sss_ncache_prepopulate,
-                                        setup, teardown)
+                                        setup, teardown),
+        cmocka_unit_test_setup_teardown(test_sss_ncache_default_domain_suffix,
+                                        setup, teardown),
     };
 
     tests_set_cwd();
diff --git a/src/util/usertools.c b/src/util/usertools.c
index 439c1494ae5f4c8c46a7e36ad7c8af627ef83cdf..c43d420e31c6c690628ef6179d932eaf99826fee 100644
--- a/src/util/usertools.c
+++ b/src/util/usertools.c
@@ -481,8 +481,7 @@ int sss_parse_name_for_domains(TALLOC_CTX *memctx,
                 }
                 if (match == NULL) {
                     DEBUG(SSSDBG_FUNC_DATA, "default domain [%s] is currently " \
-                                            "not known, trying to look it up.\n",
-                                            rdomain);
+                                            "not known\n", rdomain);
                     *domain = talloc_steal(memctx, rdomain);
                     ret = EAGAIN;
                     goto done;
-- 
2.1.0

-------------- next part --------------
>From e5745bb5384772f25850203c27a355cba5a5c374 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Sun, 29 Mar 2015 16:30:27 +0200
Subject: [PATCH 3/5] ncache: Add sss_ncache_reset_repopulate_permanent

This new function resets the negative cache and then re-adds the
permanent entries.
---
 src/responder/common/negcache.c  | 14 ++++++
 src/responder/common/negcache.h  |  6 +++
 src/tests/cmocka/test_negcache.c | 93 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 113 insertions(+)

diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c
index 3e58c3e7f3888992069dc573ae458e0da641dc7b..2fa61af53dd2d42ae4df2a3db17edf4978ed78a1 100644
--- a/src/responder/common/negcache.c
+++ b/src/responder/common/negcache.c
@@ -838,3 +838,17 @@ done:
     talloc_free(tmpctx);
     return ret;
 }
+
+/* Reset permanent negcache after checking the domains */
+errno_t sss_ncache_reset_repopulate_permanent(struct resp_ctx *rctx,
+                                              struct sss_nc_ctx *ncache)
+{
+    int ret;
+
+    ret = sss_ncache_reset_permanent(ncache);
+    if (ret == EOK) {
+        ret = sss_ncache_prepopulate(ncache, rctx->cdb, rctx);
+    }
+
+    return ret;
+}
diff --git a/src/responder/common/negcache.h b/src/responder/common/negcache.h
index 00f979dbbda164cc84f739c1fd5987137f288720..b96fbfda5a63ce32c42b31bcfe517d2369f06138 100644
--- a/src/responder/common/negcache.h
+++ b/src/responder/common/negcache.h
@@ -69,6 +69,8 @@ int sss_ncache_set_service_port(struct sss_nc_ctx *ctx, bool permanent,
 
 int sss_ncache_reset_permanent(struct sss_nc_ctx *ctx);
 
+struct resp_ctx;
+
 /* Set up the negative cache with values from filter_users and
  * filter_groups in the sssd.conf
  */
@@ -76,4 +78,8 @@ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache,
                                struct confdb_ctx *cdb,
                                struct resp_ctx *rctx);
 
+/* Flush the negcache and then repopulate */
+errno_t sss_ncache_reset_repopulate_permanent(struct resp_ctx *rctx,
+                                              struct sss_nc_ctx *ncache);
+
 #endif /* _NSS_NEG_CACHE_H_ */
diff --git a/src/tests/cmocka/test_negcache.c b/src/tests/cmocka/test_negcache.c
index 5ade3fd4b347a6c7c74754730bca4b82c71ddf06..6281ec00988cfe9acc6b915a5973d29b9b19063b 100644
--- a/src/tests/cmocka/test_negcache.c
+++ b/src/tests/cmocka/test_negcache.c
@@ -691,6 +691,97 @@ static void test_sss_ncache_default_domain_suffix(void **state)
     assert_int_equal(ret, EOK);
 }
 
+static void test_sss_ncache_reset_prepopulate(void **state)
+{
+    int ret;
+    struct test_state *ts;
+    struct tevent_context *ev;
+    struct sss_nc_ctx *ncache;
+    struct sss_test_ctx *tc;
+    struct sss_domain_info *dom;
+    struct sss_domain_info *dom2;
+
+    struct sss_test_conf_param params[] = {
+        { "filter_users", "testuser1@"TEST_DOM_NAME", testuser2@"TEST_DOM_NAME"2" },
+        { "filter_groups", "testgroup1@"TEST_DOM_NAME", testgroup2@"TEST_DOM_NAME"2" },
+        { NULL, NULL },
+    };
+
+    const char *nss_filter_users[] = { params[0].value, NULL};
+    const char *nss_filter_groups[] = { params[1].value, NULL};
+
+    ts = talloc_get_type_abort(*state, struct test_state);
+
+    ev = tevent_context_init(ts);
+    assert_non_null(ev);
+
+    dom = talloc_zero(ts, struct sss_domain_info);
+    assert_non_null(dom);
+    dom->name = discard_const_p(char, TEST_DOM_NAME);
+
+    ts->nctx = mock_nctx(ts);
+    assert_non_null(ts->nctx);
+
+    tc = create_dom_test_ctx(ts, TESTS_PATH, TEST_CONF_DB,
+                             TEST_DOM_NAME, TEST_ID_PROVIDER, params);
+    assert_non_null(tc);
+
+    ret = confdb_add_param(tc->confdb, true, "config/nss",
+                           "filter_users", nss_filter_users);
+    assert_int_equal(ret, EOK);
+
+    ret = confdb_add_param(tc->confdb, true, "config/nss",
+                           "filter_groups", nss_filter_groups);
+    assert_int_equal(ret, EOK);
+
+    ncache = ts->ctx;
+    ts->rctx = mock_rctx(ts, ev, dom, ts->nctx);
+    assert_non_null(ts->rctx);
+    ts->rctx->default_domain = discard_const(TEST_DOM_NAME);
+    ts->rctx->cdb = tc->confdb;
+
+    ret = sss_names_init(ts, tc->confdb, TEST_DOM_NAME, &dom->names);
+    assert_int_equal(ret, EOK);
+
+    ret = sss_ncache_reset_repopulate_permanent(ts->rctx, ncache);
+    assert_int_equal(ret, EOK);
+
+    /* Add another domain */
+    dom2 = talloc_zero(ts, struct sss_domain_info);
+    assert_non_null(dom2);
+    dom2->name = discard_const_p(char, TEST_DOM_NAME"2");
+    dom->next = dom2;
+    dom2->names = dom->names;
+
+    /* First domain should not be known, the second not */
+    ret = sss_ncache_check_user(ncache, 1, dom, "testuser1");
+    assert_int_equal(ret, EEXIST);
+
+    ret = sss_ncache_check_group(ncache, 1, dom, "testgroup1");
+    assert_int_equal(ret, EEXIST);
+
+    ret = sss_ncache_check_user(ncache, 1, dom2, "testuser2");
+    assert_int_equal(ret, ENOENT);
+
+    ret = sss_ncache_check_group(ncache, 1, dom2, "testgroup2");
+    assert_int_equal(ret, ENOENT);
+
+    ret = sss_ncache_reset_repopulate_permanent(ts->rctx, ncache);
+    assert_int_equal(ret, EOK);
+
+    /* First domain should not be known, the second not */
+    ret = sss_ncache_check_user(ncache, 1, dom, "testuser1");
+    assert_int_equal(ret, EEXIST);
+
+    ret = sss_ncache_check_group(ncache, 1, dom, "testgroup1");
+    assert_int_equal(ret, EEXIST);
+
+    ret = sss_ncache_check_user(ncache, 1, dom2, "testuser2");
+    assert_int_equal(ret, EEXIST);
+
+    ret = sss_ncache_check_group(ncache, 1, dom2, "testgroup2");
+    assert_int_equal(ret, EEXIST);
+}
 int main(void)
 {
     int rv;
@@ -712,6 +803,8 @@ int main(void)
                                         setup, teardown),
         cmocka_unit_test_setup_teardown(test_sss_ncache_default_domain_suffix,
                                         setup, teardown),
+        cmocka_unit_test_setup_teardown(test_sss_ncache_reset_prepopulate,
+                                        setup, teardown),
     };
 
     tests_set_cwd();
-- 
2.1.0

-------------- next part --------------
>From 0570429e64f8c42feeed8bed75bf5530d1c1fed2 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Sun, 29 Mar 2015 16:31:19 +0200
Subject: [PATCH 4/5] responders: reset ncache after domains are discovered
 during startup

After responders start, they add a lookup operation that discovers the
subdomains so that qualifying users works. After this operation is
finishes, we need to reset negcache to allow users to be added into the
newly discovered domains.
---
 src/responder/autofs/autofssrv.c             |  2 +-
 src/responder/common/responder.h             |  4 ++-
 src/responder/common/responder_get_domains.c | 42 +++++++++++++++++++++++-----
 src/responder/ifp/ifpsrv.c                   |  2 +-
 src/responder/nss/nsssrv.c                   |  2 +-
 src/responder/pac/pacsrv.c                   |  2 +-
 src/responder/pam/pamsrv.c                   |  2 +-
 src/responder/ssh/sshsrv.c                   |  2 +-
 src/responder/sudo/sudosrv.c                 |  2 +-
 src/tests/cmocka/test_responder_common.c     | 37 ++++++++++++++++++++++++
 10 files changed, 82 insertions(+), 15 deletions(-)

diff --git a/src/responder/autofs/autofssrv.c b/src/responder/autofs/autofssrv.c
index 91f529135e9bd74a5cf89edadd98fb2368630b5e..ff30167298e0028da3f14f4d63a4d129c9c70bf0 100644
--- a/src/responder/autofs/autofssrv.c
+++ b/src/responder/autofs/autofssrv.c
@@ -187,7 +187,7 @@ autofs_process_init(TALLOC_CTX *mem_ctx,
         goto fail;
     }
 
-    ret = schedule_get_domains_task(rctx, rctx->ev, rctx);
+    ret = schedule_get_domains_task(rctx, rctx->ev, rctx, NULL);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "schedule_get_domains_tasks failed.\n");
         goto fail;
diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
index 02a215ced435c87ec0439807ab5e575de0d0fe04..9c7a73809a3de8859aa546c2a7d31620fea39ac9 100644
--- a/src/responder/common/responder.h
+++ b/src/responder/common/responder.h
@@ -34,6 +34,7 @@
 #include <dhash.h>
 
 #include "sbus/sssd_dbus.h"
+#include "responder/common/negcache.h"
 #include "sss_client/sss_cli.h"
 
 extern hash_table_t *dp_requests;
@@ -314,7 +315,8 @@ errno_t sss_dp_get_domains_recv(struct tevent_req *req);
 
 errno_t schedule_get_domains_task(TALLOC_CTX *mem_ctx,
                                   struct tevent_context *ev,
-                                  struct resp_ctx *rctx);
+                                  struct resp_ctx *rctx,
+                                  struct sss_nc_ctx *optional_ncache);
 
 errno_t csv_string_to_uid_array(TALLOC_CTX *mem_ctx, const char *csv_string,
                                 bool allow_sss_loop,
diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c
index 1dbb9ea81b614a3ab83e1138c4ed30c1b48f4d1c..8fbab082aee02f6d5fae85b04bab047e59d20b44 100644
--- a/src/responder/common/responder_get_domains.c
+++ b/src/responder/common/responder_get_domains.c
@@ -363,16 +363,33 @@ static errno_t check_last_request(struct resp_ctx *rctx, const char *hint)
     return EOK;
 }
 
+struct get_domains_state {
+    struct resp_ctx *rctx;
+    struct sss_nc_ctx *optional_ncache;
+};
+
 static void get_domains_at_startup_done(struct tevent_req *req)
 {
     int ret;
+    struct get_domains_state *state;
+
+    state = tevent_req_callback_data(req, struct get_domains_state);
 
     ret = sss_dp_get_domains_recv(req);
     talloc_free(req);
     if (ret != EOK) {
-        DEBUG(SSSDBG_OP_FAILURE, "sss_dp_get_domains request failed.\n");
+        DEBUG(SSSDBG_MINOR_FAILURE, "sss_dp_get_domains request failed.\n");
     }
 
+    if (state->optional_ncache != NULL) {
+        ret = sss_ncache_reset_repopulate_permanent(state->rctx,
+                                                    state->optional_ncache);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_MINOR_FAILURE, "sss_dp_get_domains request failed.\n");
+        }
+    }
+
+    talloc_free(state);
     return;
 }
 
@@ -381,33 +398,44 @@ static void get_domains_at_startup(struct tevent_context *ev,
                                    void *pvt)
 {
     struct tevent_req *req;
-    struct resp_ctx *rctx;
+    struct get_domains_state *state;
 
-    rctx = talloc_get_type(pvt, struct resp_ctx);
+    state = talloc_get_type(pvt, struct get_domains_state);
 
-    req = sss_dp_get_domains_send(rctx, rctx, true, NULL);
+    req = sss_dp_get_domains_send(state, state->rctx, true, NULL);
     if (req == NULL) {
         DEBUG(SSSDBG_OP_FAILURE, "sss_dp_get_domains_send failed.\n");
+        talloc_free(state);
         return;
     }
 
-    tevent_req_set_callback(req, get_domains_at_startup_done, NULL);
+    tevent_req_set_callback(req, get_domains_at_startup_done, state);
     return;
 }
 
 errno_t schedule_get_domains_task(TALLOC_CTX *mem_ctx,
                                   struct tevent_context *ev,
-                                  struct resp_ctx *rctx)
+                                  struct resp_ctx *rctx,
+                                  struct sss_nc_ctx *optional_ncache)
 {
     struct tevent_immediate *imm;
+    struct get_domains_state *state;
+
+    state = talloc(mem_ctx, struct get_domains_state);
+    if (state == NULL) {
+        return ENOMEM;
+    }
+    state->rctx = rctx;
+    state->optional_ncache = optional_ncache;
 
     imm = tevent_create_immediate(mem_ctx);
     if (imm == NULL) {
         DEBUG(SSSDBG_OP_FAILURE, "tevent_create_immediate failed.\n");
+        talloc_free(state);
         return ENOMEM;
     }
 
-    tevent_schedule_immediate(imm, ev, get_domains_at_startup, rctx);
+    tevent_schedule_immediate(imm, ev, get_domains_at_startup, state);
 
     return EOK;
 }
diff --git a/src/responder/ifp/ifpsrv.c b/src/responder/ifp/ifpsrv.c
index a4cabf20aac8f91fc9cac8fc4ee3efff144cf0b8..3f5444186bf5878ca9fd15760f914892293a03b6 100644
--- a/src/responder/ifp/ifpsrv.c
+++ b/src/responder/ifp/ifpsrv.c
@@ -339,7 +339,7 @@ int ifp_process_init(TALLOC_CTX *mem_ctx,
         return EIO;
     }
 
-    ret = schedule_get_domains_task(rctx, rctx->ev, rctx);
+    ret = schedule_get_domains_task(rctx, rctx->ev, rctx, NULL);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE,
               "schedule_get_domains_tasks failed.\n");
diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c
index bce06c3e8b56f3b09126f43a194c1cd6a60efb2c..48fb19408cc10e99b79308debb7ef6c3e6bc0127 100644
--- a/src/responder/nss/nsssrv.c
+++ b/src/responder/nss/nsssrv.c
@@ -530,7 +530,7 @@ int nss_process_init(TALLOC_CTX *mem_ctx,
     }
     responder_set_fd_limit(fd_limit);
 
-    ret = schedule_get_domains_task(rctx, rctx->ev, rctx);
+    ret = schedule_get_domains_task(rctx, rctx->ev, rctx, nctx->ncache);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "schedule_get_domains_tasks failed.\n");
         goto fail;
diff --git a/src/responder/pac/pacsrv.c b/src/responder/pac/pacsrv.c
index 859ae86a54daf268c73ab97b0a1f67967d7e714f..20a5702e1cf4bfdd390ff72e8cbb00ee7b4ca964 100644
--- a/src/responder/pac/pacsrv.c
+++ b/src/responder/pac/pacsrv.c
@@ -195,7 +195,7 @@ int pac_process_init(TALLOC_CTX *mem_ctx,
     }
     responder_set_fd_limit(fd_limit);
 
-    ret = schedule_get_domains_task(rctx, rctx->ev, rctx);
+    ret = schedule_get_domains_task(rctx, rctx->ev, rctx, NULL);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "schedule_get_domains_tasks failed.\n");
         goto fail;
diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c
index 45747baa03b593a65e70f4cbd0ce022648d1333c..aa0d2796b1357d2457a7545415960bd0aaf241bf 100644
--- a/src/responder/pam/pamsrv.c
+++ b/src/responder/pam/pamsrv.c
@@ -296,7 +296,7 @@ static int pam_process_init(TALLOC_CTX *mem_ctx,
     }
     responder_set_fd_limit(fd_limit);
 
-    ret = schedule_get_domains_task(rctx, rctx->ev, rctx);
+    ret = schedule_get_domains_task(rctx, rctx->ev, rctx, pctx->ncache);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "schedule_get_domains_tasks failed.\n");
         goto done;
diff --git a/src/responder/ssh/sshsrv.c b/src/responder/ssh/sshsrv.c
index 1bcf4e21a89e4e7b7697e9d90ab239cbf9d231e9..9439b9d89ae47dc66d392f0c434f4de1c1c0b4ea 100644
--- a/src/responder/ssh/sshsrv.c
+++ b/src/responder/ssh/sshsrv.c
@@ -163,7 +163,7 @@ int ssh_process_init(TALLOC_CTX *mem_ctx,
         goto fail;
     }
 
-    ret = schedule_get_domains_task(rctx, rctx->ev, rctx);
+    ret = schedule_get_domains_task(rctx, rctx->ev, rctx, NULL);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "schedule_get_domains_tasks failed.\n");
         goto fail;
diff --git a/src/responder/sudo/sudosrv.c b/src/responder/sudo/sudosrv.c
index e480c7a43d453cffcd6ca07e41402c1cf6eef91c..5d46222c9a00c130965357fa99d322d87c4624b5 100644
--- a/src/responder/sudo/sudosrv.c
+++ b/src/responder/sudo/sudosrv.c
@@ -143,7 +143,7 @@ int sudo_process_init(TALLOC_CTX *mem_ctx,
         goto fail;
     }
 
-    ret = schedule_get_domains_task(rctx, rctx->ev, rctx);
+    ret = schedule_get_domains_task(rctx, rctx->ev, rctx, NULL);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "schedule_get_domains_tasks failed.\n");
         goto fail;
diff --git a/src/tests/cmocka/test_responder_common.c b/src/tests/cmocka/test_responder_common.c
index 44c93c1d540deade232373013f1dd1406126c1cd..0a4d4bb49c5058b5a006912b6b3b61ab0332cc29 100644
--- a/src/tests/cmocka/test_responder_common.c
+++ b/src/tests/cmocka/test_responder_common.c
@@ -266,6 +266,40 @@ void parse_inp_call_neg(void **state)
     assert_int_equal(ret, EOK);
 }
 
+struct sss_nc_ctx {
+    struct parse_inp_test_ctx *pctx;
+};
+
+errno_t sss_ncache_reset_repopulate_permanent(struct resp_ctx *rctx,
+                                              struct sss_nc_ctx *dummy_ncache_ptr)
+{
+    dummy_ncache_ptr->pctx->tctx->error = EOK;
+    dummy_ncache_ptr->pctx->tctx->done = true;
+    return EOK;
+}
+
+void test_schedule_get_domains_task(void **state)
+{
+    struct parse_inp_test_ctx *parse_inp_ctx = talloc_get_type(*state,
+                                                   struct parse_inp_test_ctx);
+    errno_t ret;
+    struct sss_nc_ctx *dummy_ncache_ptr;
+
+    dummy_ncache_ptr = talloc(parse_inp_ctx, struct sss_nc_ctx);
+    assert_non_null(dummy_ncache_ptr);
+    dummy_ncache_ptr->pctx = parse_inp_ctx;
+
+    ret = schedule_get_domains_task(dummy_ncache_ptr,
+                                    parse_inp_ctx->rctx->ev,
+                                    parse_inp_ctx->rctx,
+                                    dummy_ncache_ptr);
+    assert_int_equal(ret, EOK);
+
+    ret = test_ev_loop(parse_inp_ctx->tctx);
+    assert_int_equal(ret, EOK);
+    talloc_free(dummy_ncache_ptr);
+}
+
 int main(int argc, const char *argv[])
 {
     int rv;
@@ -293,6 +327,9 @@ int main(int argc, const char *argv[])
         cmocka_unit_test_setup_teardown(parse_inp_call_neg,
                                         parse_inp_test_setup,
                                         parse_inp_test_teardown),
+        cmocka_unit_test_setup_teardown(test_schedule_get_domains_task,
+                                        parse_inp_test_setup,
+                                        parse_inp_test_teardown),
     };
 
     /* Set debug level to invalid value so we can deside if -d 0 was used. */
-- 
2.1.0

-------------- next part --------------
>From 1d9bc4c91131dc8af1cbddeb414f0cb71069724d Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Sun, 29 Mar 2015 20:30:44 +0200
Subject: [PATCH 5/5] NSS: Reset negcache after checking domains

The NSS responder periodically re-checks subdomains. We need to reset
the negative cache each time the check finishes to allow the negative
cache to contain entries from different domains.
---
 src/responder/nss/nsssrv_cmd.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c
index 576532226f71075a4d714fc0e20cdc475ffea8db..72da865d0bbe2142799a93415f0a645ae9cac13d 100644
--- a/src/responder/nss/nsssrv_cmd.c
+++ b/src/responder/nss/nsssrv_cmd.c
@@ -105,6 +105,18 @@ struct setent_ctx {
     struct getent_ctx *getent_ctx;
 };
 
+static int nss_reset_negcache(struct resp_ctx *rctx)
+{
+    struct nss_ctx *nss_ctx;
+
+    nss_ctx = talloc_get_type(rctx->pvt_ctx, struct nss_ctx);
+    if (nss_ctx == NULL) {
+        return EIO;
+    }
+
+    return sss_ncache_reset_repopulate_permanent(rctx, nss_ctx->ncache);
+}
+
 /****************************************************************************
  * PASSWD db related functions
  ***************************************************************************/
@@ -1450,6 +1462,12 @@ static void nss_cmd_getbynam_done(struct tevent_req *req)
         goto done;
     }
 
+    ret = nss_reset_negcache(cctx->rctx);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_MINOR_FAILURE, "Cannot reset negcache records\n");
+        /* Not fatal */
+    }
+
     DEBUG(SSSDBG_TRACE_FUNC, "Requesting info for [%s] from [%s]\n",
               cmdctx->name, domname?domname:"<ALL>");
 
@@ -1808,6 +1826,12 @@ static void nss_cmd_getbyid_done(struct tevent_req *req)
         goto done;
     }
 
+    ret = nss_reset_negcache(cmdctx->cctx->rctx);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_MINOR_FAILURE, "Cannot reset negcache records\n");
+        /* Not fatal */
+    }
+
     /* ok, find it ! */
     switch(dctx->cmdctx->cmd) {
     case SSS_NSS_GETPWUID:
-- 
2.1.0



More information about the sssd-devel mailing list