Blob Blame History Raw
From 72fdce0007af1baa0504c2d11be8b19e1a3296f1 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Mon, 6 Nov 2017 10:09:16 +0100
Subject: [PATCH 76/83] NEGCACHE: Add API for setting and checking
 locate-account-domain requests
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Extends the negative cache API with several request getsetters:
    - sss_ncache_set/check_domain_locate_type - check if this request
      type supports locating account domain or set that this request
      type does not support the locator.

    - sss_ncache_set/check_locate_gid/uid - check if it is time to call
      the locator again or set that the locator should not be called
      for IDs again for the duration of the negative cache.

Reviewed-by: Pavel Březina <pbrezina@redhat.com>
Reviewed-by: Sumit Bose <sbose@redhat.com>
(cherry picked from commit 07452697a67902dc6876d2f40d364cf1eadf2431)
---
 src/responder/common/negcache.c  | 155 +++++++++++++++++++++++++++++++++++++++
 src/responder/common/negcache.h  |  64 ++++++++++++++++
 src/tests/cmocka/test_negcache.c |  75 +++++++++++++++++++
 3 files changed, 294 insertions(+)

diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c
index b751d89ee9e67eea32ec4ed0935fcd67d3e92f47..bd3c9d36805adc5cca5621c815576ac21cfbec38 100644
--- a/src/responder/common/negcache.c
+++ b/src/responder/common/negcache.c
@@ -37,6 +37,8 @@
 #define NC_GID_PREFIX NC_ENTRY_PREFIX"GID"
 #define NC_SID_PREFIX NC_ENTRY_PREFIX"SID"
 #define NC_CERT_PREFIX NC_ENTRY_PREFIX"CERT"
+#define NC_DOMAIN_ACCT_LOCATE_PREFIX NC_ENTRY_PREFIX"DOM_LOCATE"
+#define NC_DOMAIN_ACCT_LOCATE_TYPE_PREFIX NC_ENTRY_PREFIX"DOM_LOCATE_TYPE"
 
 struct sss_nc_ctx {
     struct tdb_context *tdb;
@@ -665,6 +667,159 @@ int sss_ncache_set_cert(struct sss_nc_ctx *ctx, bool permanent,
     return ret;
 }
 
+static char *domain_lookup_type_str(TALLOC_CTX *mem_ctx,
+                                    struct sss_domain_info *dom,
+                                    const char *lookup_type)
+{
+    return talloc_asprintf(mem_ctx,
+                           "%s/%s/%s",
+                           NC_DOMAIN_ACCT_LOCATE_TYPE_PREFIX,
+                           dom->name,
+                           lookup_type);
+}
+
+int sss_ncache_set_domain_locate_type(struct sss_nc_ctx *ctx,
+                                      struct sss_domain_info *dom,
+                                      const char *lookup_type)
+{
+    char *str;
+    int ret;
+
+    str = domain_lookup_type_str(ctx, dom, lookup_type);
+    if (!str) return ENOMEM;
+
+    /* Permanent cache is always used here, because whether the lookup
+     * type (getgrgid, getpwuid, ..) supports locating an entry's domain
+     * doesn't change
+     */
+    ret = sss_ncache_set_str(ctx, str, true, false);
+    talloc_free(str);
+    return ret;
+}
+
+int sss_ncache_check_domain_locate_type(struct sss_nc_ctx *ctx,
+                                        struct sss_domain_info *dom,
+                                        const char *lookup_type)
+{
+    char *str;
+    int ret;
+
+    str = domain_lookup_type_str(ctx, dom, lookup_type);
+    if (!str) return ENOMEM;
+
+    ret = sss_ncache_check_str(ctx, str);
+    talloc_free(str);
+    return ret;
+}
+
+static char *locate_gid_str(TALLOC_CTX *mem_ctx,
+                            struct sss_domain_info *dom,
+                            gid_t gid)
+{
+    return talloc_asprintf(mem_ctx,
+                           "%s/%s/%s/%"SPRIgid,
+                           NC_DOMAIN_ACCT_LOCATE_PREFIX,
+                           NC_GID_PREFIX,
+                           dom->name,
+                           gid);
+}
+
+int sss_ncache_set_locate_gid(struct sss_nc_ctx *ctx,
+                              struct sss_domain_info *dom,
+                              gid_t gid)
+{
+    char *str;
+    int ret;
+
+    if (dom == NULL) {
+        return EINVAL;
+    }
+
+    str = locate_gid_str(ctx, dom, gid);
+    if (str == NULL) {
+        return ENOMEM;
+    }
+
+    ret = sss_ncache_set_str(ctx, str, false, false);
+    talloc_free(str);
+    return ret;
+}
+
+int sss_ncache_check_locate_gid(struct sss_nc_ctx *ctx,
+                                struct sss_domain_info *dom,
+                                gid_t gid)
+{
+    char *str;
+    int ret;
+
+    if (dom == NULL) {
+        return EINVAL;
+    }
+
+    str = locate_gid_str(ctx, dom, gid);
+    if (str == NULL) {
+        return ENOMEM;
+    }
+
+    ret = sss_ncache_check_str(ctx, str);
+    talloc_free(str);
+    return ret;
+}
+
+static char *locate_uid_str(struct sss_nc_ctx *ctx,
+                            struct sss_domain_info *dom,
+                            uid_t uid)
+{
+    return talloc_asprintf(ctx,
+                           "%s/%s/%s/%"SPRIuid,
+                           NC_DOMAIN_ACCT_LOCATE_PREFIX,
+                           NC_UID_PREFIX,
+                           dom->name,
+                           uid);
+}
+
+int sss_ncache_set_locate_uid(struct sss_nc_ctx *ctx,
+                              struct sss_domain_info *dom,
+                              uid_t uid)
+{
+    char *str;
+    int ret;
+
+    if (dom == NULL) {
+        return EINVAL;
+    }
+
+    str = locate_uid_str(ctx, dom, uid);
+    if (str == NULL) {
+        return ENOMEM;
+    }
+
+    ret = sss_ncache_set_str(ctx, str, false, false);
+    talloc_free(str);
+    return ret;
+}
+
+int sss_ncache_check_locate_uid(struct sss_nc_ctx *ctx,
+                                struct sss_domain_info *dom,
+                                uid_t uid)
+{
+    char *str;
+    int ret;
+
+    if (dom == NULL) {
+        return EINVAL;
+    }
+
+    str = locate_uid_str(ctx, dom, uid);
+    if (str == NULL) {
+        return ENOMEM;
+    }
+
+    ret = sss_ncache_check_str(ctx, str);
+    talloc_free(str);
+    return ret;
+}
+
 static int delete_permanent(struct tdb_context *tdb,
                             TDB_DATA key, TDB_DATA data, void *state)
 {
diff --git a/src/responder/common/negcache.h b/src/responder/common/negcache.h
index 782ec140fb7dfe3ec82bed8d25290c0f7b8a36ea..2ed38e5b9a64d3393513ea2110a7c6fcb7675623 100644
--- a/src/responder/common/negcache.h
+++ b/src/responder/common/negcache.h
@@ -80,6 +80,70 @@ int sss_ncache_set_service_name(struct sss_nc_ctx *ctx, bool permanent,
 int sss_ncache_set_service_port(struct sss_nc_ctx *ctx, bool permanent,
                                 struct sss_domain_info *dom,
                                 uint16_t port, const char *proto);
+/*
+ * Mark the lookup_type as not supporting the negative cache. This
+ * would be used by the corresponding checker to avoid needless
+ * subsequent calls to the locator for configurations that do not
+ * support the locator plugin.
+ *
+ * @param ctx   The negative cache
+ * @param dom   The top-level domain. It is expected that the caller
+ *              would use the top-level domain head here, because
+ *              this negative cache is "per-request-type" which is the
+ *              same for all subdomains of a domain
+ * @param lookup_type   Lookup type, e.g. getpwuid, getgrnam.
+ *
+ * @return EOK on success, errno on failure.
+ */
+int sss_ncache_set_domain_locate_type(struct sss_nc_ctx *ctx,
+                                      struct sss_domain_info *dom,
+                                      const char *lookup_type);
+/*
+ * Check if the lookup_type supports the domain locator request.
+ *
+ * @param ctx   The negative cache
+ * @param dom   The top-level domain. It is expected that the caller
+ *              would use the top-level domain head here, because
+ *              this negative cache is "per-request-type" which is the
+ *              same for all subdomains of a domain
+ * @param lookup_type   Lookup type, e.g. getpwuid, getgrnam.
+ *
+ * @return      ENOENT if the request supports the locator (or we
+ *              haven't checked yet), EEXIST if the request does
+ *              not support the domain locator request.
+ */
+int sss_ncache_check_domain_locate_type(struct sss_nc_ctx *ctx,
+                                        struct sss_domain_info *dom,
+                                        const char *key);
+
+/*
+ * Call these two functions to mark a GID as checked until the negative
+ * cache expires. This function is used to avoid a situation where
+ * GID would be found in a subsequent domain, so any request that
+ * searches for this GID again (even if it was cached) would first
+ * run the locator again.
+ *
+ * While this negative cache entry is valid, it is expected that
+ * the negatively cached entries in the domain's GID negative
+ * cache (if any) are valid
+ *
+ * The sss_ncache_set_locate_gid() is called by the locator request
+ * when it finishes, the sss_ncache_check_locate_gid() is called
+ * by the caller of the locator request to find if the locator
+ * should be called at all.
+ */
+int sss_ncache_set_locate_gid(struct sss_nc_ctx *ctx,
+                              struct sss_domain_info *dom,
+                              gid_t gid);
+int sss_ncache_check_locate_gid(struct sss_nc_ctx *ctx,
+                                struct sss_domain_info *dom,
+                                gid_t gid);
+int sss_ncache_check_locate_uid(struct sss_nc_ctx *ctx,
+                                struct sss_domain_info *dom,
+                                uid_t uid);
+int sss_ncache_set_locate_uid(struct sss_nc_ctx *ctx,
+                              struct sss_domain_info *dom,
+                              uid_t uid);
 
 int sss_ncache_reset_permanent(struct sss_nc_ctx *ctx);
 int sss_ncache_reset_users(struct sss_nc_ctx *ctx);
diff --git a/src/tests/cmocka/test_negcache.c b/src/tests/cmocka/test_negcache.c
index ba39f778d5ddc6a4e1708aef66fc2aa1c809f150..a0210928bd60e364c60717c8b37b2405730f34ab 100644
--- a/src/tests/cmocka/test_negcache.c
+++ b/src/tests/cmocka/test_negcache.c
@@ -883,6 +883,77 @@ static void test_sss_ncache_reset(void **state)
     assert_int_equal(ret, ENOENT);
 }
 
+static void test_sss_ncache_locate_uid_gid(void **state)
+{
+    uid_t uid;
+    gid_t gid;
+    int ret;
+    struct test_state *ts;
+    struct sss_domain_info *dom;
+    struct sss_domain_info *dom2;
+
+    ts = talloc_get_type_abort(*state, struct test_state);
+
+    uid = getuid();
+    gid = getgid();
+
+    dom = talloc(ts, struct sss_domain_info);
+    assert_non_null(dom);
+    dom->name = discard_const_p(char, TEST_DOM_NAME);
+
+    dom2 = talloc(ts, struct sss_domain_info);
+    assert_non_null(dom2);
+    dom2->name = discard_const_p(char, TEST_DOM_NAME"2");
+
+    ret = sss_ncache_check_locate_gid(ts->ctx, dom, gid);
+    assert_int_equal(ret, ENOENT);
+    ret = sss_ncache_check_locate_uid(ts->ctx, dom, uid);
+    assert_int_equal(ret, ENOENT);
+
+    ret = sss_ncache_set_locate_gid(ts->ctx, dom, gid);
+    assert_int_equal(ret, EOK);
+    ret = sss_ncache_set_locate_uid(ts->ctx, dom, uid);
+    assert_int_equal(ret, EOK);
+
+    ret = sss_ncache_check_locate_gid(ts->ctx, dom, gid);
+    assert_int_equal(ret, EEXIST);
+    ret = sss_ncache_check_locate_uid(ts->ctx, dom, uid);
+    assert_int_equal(ret, EEXIST);
+
+    ret = sss_ncache_check_locate_gid(ts->ctx, dom2, gid);
+    assert_int_equal(ret, ENOENT);
+    ret = sss_ncache_check_locate_uid(ts->ctx, dom2, uid);
+    assert_int_equal(ret, ENOENT);
+}
+
+static void test_sss_ncache_domain_locate_type(void **state)
+{
+    int ret;
+    struct test_state *ts;
+    struct sss_domain_info *dom;
+    struct sss_domain_info *dom2;
+
+    ts = talloc_get_type_abort(*state, struct test_state);
+
+    dom = talloc(ts, struct sss_domain_info);
+    assert_non_null(dom);
+    dom->name = discard_const_p(char, TEST_DOM_NAME);
+
+    dom2 = talloc(ts, struct sss_domain_info);
+    assert_non_null(dom2);
+    dom2->name = discard_const_p(char, TEST_DOM_NAME"2");
+
+    ret = sss_ncache_check_domain_locate_type(ts->ctx, dom, "foo");
+    assert_int_equal(ret, ENOENT);
+    ret = sss_ncache_set_domain_locate_type(ts->ctx, dom, "foo");
+    assert_int_equal(ret, EOK);
+    ret = sss_ncache_check_domain_locate_type(ts->ctx, dom, "foo");
+    assert_int_equal(ret, EEXIST);
+
+    ret = sss_ncache_check_domain_locate_type(ts->ctx, dom2, "foo");
+    assert_int_equal(ret, ENOENT);
+}
+
 int main(void)
 {
     int rv;
@@ -909,6 +980,10 @@ int main(void)
                                         setup, teardown),
         cmocka_unit_test_setup_teardown(test_sss_ncache_reset,
                                         setup, teardown),
+        cmocka_unit_test_setup_teardown(test_sss_ncache_locate_uid_gid,
+                                        setup, teardown),
+        cmocka_unit_test_setup_teardown(test_sss_ncache_domain_locate_type,
+                                        setup, teardown),
     };
 
     tests_set_cwd();
-- 
2.14.3