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