From e7ccfb139388c947ec2dee16cfe3005f5643b90d Mon Sep 17 00:00:00 2001 From: Petr Cech Date: Thu, 5 May 2016 11:16:14 -0400 Subject: RESPONDERS: Negative caching of local users MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds new option 'neg_cache_locals_timeout' into section of NSS responder. It allows negative caching of local groups and users. Default value is 0 which means no caching. Resolves: https://fedorahosted.org/sssd/ticket/2928 Reviewed-by: Pavel Březina --- Makefile.am | 4 ++ src/confdb/confdb.h | 1 + src/config/SSSDConfig/__init__.py.in | 1 + src/config/etc/sssd.api.conf | 1 + src/man/sssd.conf.5.xml | 13 ++++ src/responder/common/negcache.c | 45 +++++++++---- src/responder/common/negcache.h | 2 +- src/responder/common/negcache_files.c | 98 +++++++++++++++++++++++++++++ src/responder/common/negcache_files.h | 31 +++++++++ src/responder/common/responder_common.c | 22 ++++++- src/tests/cmocka/common_mock_resp.c | 2 +- src/tests/cmocka/test_negcache.c | 4 +- src/tests/cmocka/test_responder_cache_req.c | 4 +- src/tests/cwrap/Makefile.am | 1 + 14 files changed, 209 insertions(+), 20 deletions(-) create mode 100644 src/responder/common/negcache_files.c create mode 100644 src/responder/common/negcache_files.h diff --git a/Makefile.am b/Makefile.am index 25130b105..ee8f698d6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -457,6 +457,7 @@ AM_CPPFLAGS = \ EXTRA_DIST = SSSD_RESPONDER_OBJ = \ + src/responder/common/negcache_files.c \ src/responder/common/negcache.c \ src/responder/common/responder_cmd.c \ src/responder/common/responder_common.c \ @@ -582,6 +583,7 @@ dist_noinst_HEADERS = \ src/responder/nss/nsssrv_services.h \ src/responder/nss/nsssrv_mmap_cache.h \ src/responder/pac/pacsrv.h \ + src/responder/common/negcache_files.h \ src/responder/common/negcache.h \ src/responder/sudo/sudosrv_private.h \ src/responder/autofs/autofs_private.h \ @@ -1852,6 +1854,7 @@ sss_idmap_tests_LDADD = \ responder_socket_access_tests_SOURCES = \ src/tests/responder_socket_access-tests.c \ + src/responder/common/negcache_files.c \ src/responder/common/negcache.c \ src/responder/common/responder_common.c \ src/responder/common/responder_packet.c \ @@ -1949,6 +1952,7 @@ TEST_MOCK_RESP_OBJ = \ src/tests/cmocka/common_mock_resp_dp.c \ src/responder/common/responder_packet.c \ src/responder/common/responder_cmd.c \ + src/responder/common/negcache_files.c \ src/responder/common/negcache.c \ src/responder/common/responder_common.c \ src/responder/common/responder_cache_req.c diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h index a9b1c4362..3ed82ca0a 100644 --- a/src/confdb/confdb.h +++ b/src/confdb/confdb.h @@ -85,6 +85,7 @@ #define CONFDB_RESPONDER_GET_DOMAINS_TIMEOUT "get_domains_timeout" #define CONFDB_RESPONDER_CLI_IDLE_TIMEOUT "client_idle_timeout" #define CONFDB_RESPONDER_CLI_IDLE_DEFAULT_TIMEOUT 60 +#define CONFDB_RESPONDER_LOCAL_NEG_TIMEOUT "local_negative_timeout" /* NSS */ #define CONFDB_NSS_CONF_ENTRY "config/nss" diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in index e7bf43dfd..abbf5dca8 100644 --- a/src/config/SSSDConfig/__init__.py.in +++ b/src/config/SSSDConfig/__init__.py.in @@ -67,6 +67,7 @@ option_strings = { 'enum_cache_timeout' : _('Enumeration cache timeout length (seconds)'), 'entry_cache_no_wait_timeout' : _('Entry cache background update timeout length (seconds)'), 'entry_negative_timeout' : _('Negative cache timeout length (seconds)'), + 'local_negative_timeout' : _('Files negative cache timeout length (seconds)'), 'filter_users' : _('Users that SSSD should explicitly ignore'), 'filter_groups' : _('Groups that SSSD should explicitly ignore'), 'filter_users_in_groups' : _('Should filtered users appear in groups'), diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf index a0a82543f..fef55364d 100644 --- a/src/config/etc/sssd.api.conf +++ b/src/config/etc/sssd.api.conf @@ -33,6 +33,7 @@ certificate_verification = str, None, false enum_cache_timeout = int, None, false entry_cache_nowait_percentage = int, None, false entry_negative_timeout = int, None, false +local_negative_timeout = int, None, false filter_users = list, str, false filter_groups = list, str, false filter_users_in_groups = bool, None, false diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml index 6cff0dc87..b82e94156 100644 --- a/src/man/sssd.conf.5.xml +++ b/src/man/sssd.conf.5.xml @@ -612,6 +612,19 @@ + + local_negative_timeout (integer) + + + Specifies for how many seconds nss_sss should keep + local users and groups in negative cache before + trying to look it up in the back end again. + + + Default: 0 + + + filter_users, filter_groups (string) diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c index 1488c12a8..025455238 100644 --- a/src/responder/common/negcache.c +++ b/src/responder/common/negcache.c @@ -21,6 +21,7 @@ #include "util/util.h" #include "confdb/confdb.h" +#include "responder/common/negcache_files.h" #include "responder/common/responder.h" #include "responder/common/negcache.h" #include @@ -40,6 +41,7 @@ struct sss_nc_ctx { struct tdb_context *tdb; uint32_t timeout; + uint32_t local_timeout; }; typedef int (*ncache_set_byname_fn_t)(struct sss_nc_ctx *, bool, @@ -59,8 +61,8 @@ static int string_to_tdb_data(char *str, TDB_DATA *ret) return EOK; } -int sss_ncache_init(TALLOC_CTX *memctx, uint32_t timeout, - struct sss_nc_ctx **_ctx) +int sss_ncache_init(TALLOC_CTX *memctx, uint32_t timeout, + uint32_t local_timeout, struct sss_nc_ctx **_ctx) { struct sss_nc_ctx *ctx; @@ -73,6 +75,7 @@ int sss_ncache_init(TALLOC_CTX *memctx, uint32_t timeout, if (!ctx->tdb) return errno; ctx->timeout = timeout; + ctx->local_timeout = local_timeout; *_ctx = ctx; return EOK; @@ -139,8 +142,8 @@ done: return ret; } -static int sss_ncache_set_str(struct sss_nc_ctx *ctx, - char *str, bool permanent) +static int sss_ncache_set_str(struct sss_nc_ctx *ctx, char *str, + bool permanent, bool is_local) { TDB_DATA key; TDB_DATA data; @@ -154,7 +157,15 @@ static int sss_ncache_set_str(struct sss_nc_ctx *ctx, if (permanent) { timest = talloc_strdup(ctx, "0"); } else { - timell = (unsigned long long int)time(NULL) + ctx->timeout; + if (is_local == true && ctx->local_timeout > 0) { + timell = (unsigned long long int)time(NULL) + ctx->local_timeout; + } else { + if (ctx->timeout > 0) { + timell = (unsigned long long int)time(NULL) + ctx->timeout; + } else { + return EOK; + } + } timest = talloc_asprintf(ctx, "%llu", timell); } if (!timest) return ENOMEM; @@ -300,7 +311,7 @@ static int sss_ncache_set_service_int(struct sss_nc_ctx *ctx, bool permanent, str = talloc_asprintf(ctx, "%s/%s/%s", NC_SERVICE_PREFIX, domain, name); if (!str) return ENOMEM; - ret = sss_ncache_set_str(ctx, str, permanent); + ret = sss_ncache_set_str(ctx, str, permanent, false); talloc_free(str); return ret; @@ -446,6 +457,7 @@ int sss_ncache_check_cert(struct sss_nc_ctx *ctx, const char *cert) static int sss_ncache_set_user_int(struct sss_nc_ctx *ctx, bool permanent, const char *domain, const char *name) { + bool is_local; char *str; int ret; @@ -454,7 +466,8 @@ static int sss_ncache_set_user_int(struct sss_nc_ctx *ctx, bool permanent, str = talloc_asprintf(ctx, "%s/%s/%s", NC_USER_PREFIX, domain, name); if (!str) return ENOMEM; - ret = sss_ncache_set_str(ctx, str, permanent); + is_local = is_user_local_by_name(name); + ret = sss_ncache_set_str(ctx, str, permanent, is_local); talloc_free(str); return ret; @@ -463,6 +476,7 @@ static int sss_ncache_set_user_int(struct sss_nc_ctx *ctx, bool permanent, static int sss_ncache_set_group_int(struct sss_nc_ctx *ctx, bool permanent, const char *domain, const char *name) { + bool is_local; char *str; int ret; @@ -471,7 +485,8 @@ static int sss_ncache_set_group_int(struct sss_nc_ctx *ctx, bool permanent, str = talloc_asprintf(ctx, "%s/%s/%s", NC_GROUP_PREFIX, domain, name); if (!str) return ENOMEM; - ret = sss_ncache_set_str(ctx, str, permanent); + is_local = is_group_local_by_name(name); + ret = sss_ncache_set_str(ctx, str, permanent, is_local); talloc_free(str); return ret; @@ -488,7 +503,7 @@ static int sss_ncache_set_netgr_int(struct sss_nc_ctx *ctx, bool permanent, str = talloc_asprintf(ctx, "%s/%s/%s", NC_NETGROUP_PREFIX, domain, name); if (!str) return ENOMEM; - ret = sss_ncache_set_str(ctx, str, permanent); + ret = sss_ncache_set_str(ctx, str, permanent, false); talloc_free(str); return ret; @@ -535,6 +550,7 @@ int sss_ncache_set_netgr(struct sss_nc_ctx *ctx, bool permanent, int sss_ncache_set_uid(struct sss_nc_ctx *ctx, bool permanent, struct sss_domain_info *dom, uid_t uid) { + bool is_local; char *str; int ret; @@ -546,7 +562,8 @@ int sss_ncache_set_uid(struct sss_nc_ctx *ctx, bool permanent, } if (!str) return ENOMEM; - ret = sss_ncache_set_str(ctx, str, permanent); + is_local = is_user_local_by_uid(uid); + ret = sss_ncache_set_str(ctx, str, permanent, is_local); talloc_free(str); return ret; @@ -555,6 +572,7 @@ int sss_ncache_set_uid(struct sss_nc_ctx *ctx, bool permanent, int sss_ncache_set_gid(struct sss_nc_ctx *ctx, bool permanent, struct sss_domain_info *dom, gid_t gid) { + bool is_local; char *str; int ret; @@ -566,7 +584,8 @@ int sss_ncache_set_gid(struct sss_nc_ctx *ctx, bool permanent, } if (!str) return ENOMEM; - ret = sss_ncache_set_str(ctx, str, permanent); + is_local = is_group_local_by_gid(gid); + ret = sss_ncache_set_str(ctx, str, permanent, is_local); talloc_free(str); return ret; @@ -580,7 +599,7 @@ int sss_ncache_set_sid(struct sss_nc_ctx *ctx, bool permanent, const char *sid) str = talloc_asprintf(ctx, "%s/%s", NC_SID_PREFIX, sid); if (!str) return ENOMEM; - ret = sss_ncache_set_str(ctx, str, permanent); + ret = sss_ncache_set_str(ctx, str, permanent, false); talloc_free(str); return ret; @@ -595,7 +614,7 @@ int sss_ncache_set_cert(struct sss_nc_ctx *ctx, bool permanent, str = talloc_asprintf(ctx, "%s/%s", NC_CERT_PREFIX, cert); if (!str) return ENOMEM; - ret = sss_ncache_set_str(ctx, str, permanent); + ret = sss_ncache_set_str(ctx, str, permanent, false); talloc_free(str); return ret; diff --git a/src/responder/common/negcache.h b/src/responder/common/negcache.h index 572c723cc..377f97c8b 100644 --- a/src/responder/common/negcache.h +++ b/src/responder/common/negcache.h @@ -26,7 +26,7 @@ struct sss_nc_ctx; /* init the in memory negative cache */ int sss_ncache_init(TALLOC_CTX *memctx, uint32_t timeout, - struct sss_nc_ctx **_ctx); + uint32_t local_timeout, struct sss_nc_ctx **_ctx); uint32_t sss_ncache_get_timeout(struct sss_nc_ctx *ctx); diff --git a/src/responder/common/negcache_files.c b/src/responder/common/negcache_files.c new file mode 100644 index 000000000..1b9a4be43 --- /dev/null +++ b/src/responder/common/negcache_files.c @@ -0,0 +1,98 @@ +/* + SSSD + + NSS Responder + + Copyright (C) Petr Čech 2016 + + 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 . +*/ + +#include +#include +#include +#include "util/util.h" +#include "responder/common/negcache_files.h" + +#define BUFFER_SIZE 16384 + +bool is_user_local_by_name(const char *name) +{ + struct passwd pwd = { 0 }; + struct passwd *pwd_result; + char buffer[BUFFER_SIZE]; + bool is_local = false; + int ret; + + ret = getpwnam_r(name, &pwd, buffer, BUFFER_SIZE, &pwd_result); + if (ret == EOK && pwd_result != NULL) { + DEBUG(SSSDBG_TRACE_FUNC, "User %s is a local user\n", name); + is_local = true; + } + + return is_local; +} + +bool is_user_local_by_uid(uid_t uid) +{ + struct passwd pwd = { 0 }; + struct passwd *pwd_result; + char buffer[BUFFER_SIZE]; + bool is_local = false; + int ret; + + ret = getpwuid_r(uid, &pwd, buffer, BUFFER_SIZE, &pwd_result); + if (ret == EOK && pwd_result != NULL) { + DEBUG(SSSDBG_TRACE_FUNC, + "User with UID %"SPRIuid" is a local user\n", uid); + is_local = true; + } + + return is_local; +} + +bool is_group_local_by_name(const char *name) +{ + struct group grp = { 0 }; + struct group *grp_result; + char buffer[BUFFER_SIZE]; + bool is_local = false; + int ret; + + ret = getgrnam_r(name, &grp, buffer, BUFFER_SIZE, &grp_result); + if (ret == EOK && grp_result != NULL) { + DEBUG(SSSDBG_TRACE_FUNC, "Group %s is a local group\n", name); + is_local = true; + } + + return is_local; +} + +bool is_group_local_by_gid(uid_t gid) +{ + struct group grp = { 0 }; + struct group *grp_result; + char buffer[BUFFER_SIZE]; + bool is_local = false; + int ret; + + ret = getgrgid_r(gid, &grp, buffer, BUFFER_SIZE, &grp_result); + if (ret == EOK && grp_result != NULL) { + DEBUG(SSSDBG_TRACE_FUNC, + "Group with GID %"SPRIgid" is a local group\n", gid); + is_local = true; + } + + return is_local; +} diff --git a/src/responder/common/negcache_files.h b/src/responder/common/negcache_files.h new file mode 100644 index 000000000..01d9f0828 --- /dev/null +++ b/src/responder/common/negcache_files.h @@ -0,0 +1,31 @@ +/* + SSSD + + NSS Responder + + Copyright (C) Petr Čech 2016 + + 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 . +*/ + +#ifndef _NEGCACHE_FILES_H_ +#define _NEGCACHE_FILES_H_ + +bool is_user_local_by_name(const char *name); +bool is_user_local_by_uid(uid_t uid); + +bool is_group_local_by_name(const char *name); +bool is_group_local_by_gid(uid_t gid); + +#endif /* _NEGCACHE_FILES_H_ */ diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c index 883b22a65..f0ddde9c0 100644 --- a/src/responder/common/responder_common.c +++ b/src/responder/common/responder_common.c @@ -761,6 +761,7 @@ static errno_t responder_init_ncache(TALLOC_CTX *mem_ctx, struct sss_nc_ctx **ncache) { uint32_t neg_timeout; + uint32_t locals_timeout; int tmp_value; int ret; @@ -783,8 +784,27 @@ static errno_t responder_init_ncache(TALLOC_CTX *mem_ctx, neg_timeout = tmp_value; ret = EOK; + /* local_timeout */ + ret = confdb_get_int(cdb, CONFDB_NSS_CONF_ENTRY, + CONFDB_RESPONDER_LOCAL_NEG_TIMEOUT, + 0, &tmp_value); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Fatal failure of setup negative cache timeout.\n"); + ret = ENOENT; + goto done; + } + + if (tmp_value < 0) { + ret = EINVAL; + goto done; + } + + locals_timeout = tmp_value; + ret = EOK; + /* negative cache init */ - ret = sss_ncache_init(mem_ctx, neg_timeout, ncache); + ret = sss_ncache_init(mem_ctx, neg_timeout, locals_timeout, ncache); if (ret != EOK) { DEBUG(SSSDBG_FATAL_FAILURE, "Fatal failure of initializing negative cache.\n"); diff --git a/src/tests/cmocka/common_mock_resp.c b/src/tests/cmocka/common_mock_resp.c index 8bcf18b80..ce73d1b45 100644 --- a/src/tests/cmocka/common_mock_resp.c +++ b/src/tests/cmocka/common_mock_resp.c @@ -42,7 +42,7 @@ mock_rctx(TALLOC_CTX *mem_ctx, return NULL; } - ret = sss_ncache_init(rctx, 10, &rctx->ncache); + ret = sss_ncache_init(rctx, 10, 0, &rctx->ncache); if (ret != EOK) { talloc_free(rctx); return NULL; diff --git a/src/tests/cmocka/test_negcache.c b/src/tests/cmocka/test_negcache.c index e309ce645..8911774e3 100644 --- a/src/tests/cmocka/test_negcache.c +++ b/src/tests/cmocka/test_negcache.c @@ -104,7 +104,7 @@ static int setup(void **state) ts = talloc(NULL, struct test_state); assert_non_null(ts); - ret = sss_ncache_init(ts, SHORTSPAN, &ts->ctx); + ret = sss_ncache_init(ts, SHORTSPAN, 0, &ts->ctx); assert_int_equal(ret, EOK); assert_non_null(ts->ctx); @@ -128,7 +128,7 @@ static void test_sss_ncache_init(void **state) memctx = talloc_new(NULL); assert_non_null(memctx); - ret = sss_ncache_init(memctx, SHORTSPAN, &ctx ); + ret = sss_ncache_init(memctx, SHORTSPAN, 0, &ctx); assert_int_equal(ret, EOK); assert_non_null(ctx); diff --git a/src/tests/cmocka/test_responder_cache_req.c b/src/tests/cmocka/test_responder_cache_req.c index 6c13500ce..f30f1eaad 100644 --- a/src/tests/cmocka/test_responder_cache_req.c +++ b/src/tests/cmocka/test_responder_cache_req.c @@ -434,7 +434,7 @@ static int test_single_domain_setup(void **state) test_ctx->tctx->dom, NULL); assert_non_null(test_ctx->rctx); - ret = sss_ncache_init(test_ctx, 10, &test_ctx->ncache); + ret = sss_ncache_init(test_ctx, 10, 0, &test_ctx->ncache); assert_int_equal(ret, EOK); check_leaks_push(test_ctx); @@ -480,7 +480,7 @@ static int test_multi_domain_setup(void **state) test_ctx->tctx->dom, NULL); assert_non_null(test_ctx->rctx); - ret = sss_ncache_init(test_ctx, 10, &test_ctx->ncache); + ret = sss_ncache_init(test_ctx, 10, 0, &test_ctx->ncache); assert_int_equal(ret, EOK); check_leaks_push(test_ctx); diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am index abf50a56f..8f4d9f7ea 100644 --- a/src/tests/cwrap/Makefile.am +++ b/src/tests/cwrap/Makefile.am @@ -112,6 +112,7 @@ endif responder_common_tests_SOURCES =\ test_responder_common.c \ + ../../../src/responder/common/negcache_files.c \ ../../../src/responder/common/negcache.c \ ../../../src/responder/common/responder_common.c \ ../../../src/responder/common/responder_packet.c \ -- cgit