From 72fdce0007af1baa0504c2d11be8b19e1a3296f1 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek 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 Reviewed-by: Sumit Bose (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