sssd/0008-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch

365 lines
13 KiB
Diff

From 55f7d8034d783c01789d76a2b9ffc901045e8af8 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Tue, 24 Oct 2017 14:10:53 +0200
Subject: [PATCH 08/11] NSS: add support for SSS_NSS_EX_FLAG_INVALIDATE_CACHE
The patch adds support for the SSS_NSS_EX_FLAG_INVALIDATE_CACHE flag and
makes the existing code more flexible and handle additional flags.
If SSS_NSS_EX_FLAG_INVALIDATE_CACHE is set the requested object is only
looked up in the cache and if it was found on-disk and memory cache
entries will be invalidated.
Related to https://pagure.io/SSSD/sssd/issue/2478
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
src/responder/nss/nss_cmd.c | 141 +++++++++++++++++++++++++++++++--
src/responder/nss/nss_protocol.c | 1 +
src/responder/nss/nss_protocol.h | 1 +
src/responder/nss/nss_protocol_grent.c | 9 ++-
src/responder/nss/nss_protocol_pwent.c | 6 +-
src/sss_client/idmap/sss_nss_ex.c | 20 ++++-
src/sss_client/idmap/sss_nss_idmap.h | 8 +-
7 files changed, 171 insertions(+), 15 deletions(-)
diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c
index c5ddd2f2cc2122cd169ea991b94a14eb5bad095f..545257a0be7e91e9de767a57848bb77c5791db4e 100644
--- a/src/responder/nss/nss_cmd.c
+++ b/src/responder/nss/nss_cmd.c
@@ -50,6 +50,26 @@ nss_cmd_ctx_create(TALLOC_CTX *mem_ctx,
return cmd_ctx;
}
+static errno_t eval_flags(struct nss_cmd_ctx *cmd_ctx,
+ struct cache_req_data *data)
+{
+ if ((cmd_ctx->flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0
+ && (cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Flags SSS_NSS_EX_FLAG_NO_CACHE and "
+ "SSS_NSS_EX_FLAG_INVALIDATE_CACHE are "
+ "mutually exclusive.\n");
+ return EINVAL;
+ }
+
+ if ((cmd_ctx->flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) {
+ cache_req_data_set_bypass_cache(data, true);
+ } else if ((cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) {
+ cache_req_data_set_bypass_dp(data, true);
+ }
+
+ return EOK;
+}
+
static void nss_getby_done(struct tevent_req *subreq);
static void nss_getlistby_done(struct tevent_req *subreq);
@@ -65,7 +85,6 @@ static errno_t nss_getby_name(struct cli_ctx *cli_ctx,
struct tevent_req *subreq;
const char *rawname;
errno_t ret;
- uint32_t flags = 0;
cmd_ctx = nss_cmd_ctx_create(cli_ctx, cli_ctx, type, fill_fn);
if (cmd_ctx == NULL) {
@@ -73,8 +92,9 @@ static errno_t nss_getby_name(struct cli_ctx *cli_ctx,
goto done;
}
+ cmd_ctx->flags = 0;
if (ex_version) {
- ret = nss_protocol_parse_name_ex(cli_ctx, &rawname, &flags);
+ ret = nss_protocol_parse_name_ex(cli_ctx, &rawname, &cmd_ctx->flags);
} else {
ret = nss_protocol_parse_name(cli_ctx, &rawname);
}
@@ -92,8 +112,10 @@ static errno_t nss_getby_name(struct cli_ctx *cli_ctx,
goto done;
}
- if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) {
- cache_req_data_set_bypass_cache(data, true);
+ ret = eval_flags(cmd_ctx, data);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "eval_flags failed.\n");
+ goto done;
}
subreq = nss_get_object_send(cmd_ctx, cli_ctx->ev, cli_ctx,
@@ -129,7 +151,6 @@ static errno_t nss_getby_id(struct cli_ctx *cli_ctx,
struct tevent_req *subreq;
uint32_t id;
errno_t ret;
- uint32_t flags = 0;
cmd_ctx = nss_cmd_ctx_create(cli_ctx, cli_ctx, type, fill_fn);
if (cmd_ctx == NULL) {
@@ -138,7 +159,7 @@ static errno_t nss_getby_id(struct cli_ctx *cli_ctx,
}
if (ex_version) {
- ret = nss_protocol_parse_id_ex(cli_ctx, &id, &flags);
+ ret = nss_protocol_parse_id_ex(cli_ctx, &id, &cmd_ctx->flags);
} else {
ret = nss_protocol_parse_id(cli_ctx, &id);
}
@@ -156,8 +177,10 @@ static errno_t nss_getby_id(struct cli_ctx *cli_ctx,
goto done;
}
- if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) {
- cache_req_data_set_bypass_cache(data, true);
+ ret = eval_flags(cmd_ctx, data);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "eval_flags failed.\n");
+ goto done;
}
subreq = nss_get_object_send(cmd_ctx, cli_ctx->ev, cli_ctx,
@@ -425,6 +448,98 @@ done:
return EOK;
}
+static errno_t invalidate_cache(struct nss_cmd_ctx *cmd_ctx,
+ struct cache_req_result *result)
+{
+ int ret;
+ enum sss_mc_type memcache_type;
+ const char *name;
+ char *output_name = NULL;
+ bool is_user;
+ struct sysdb_attrs *attrs = NULL;
+
+ switch (cmd_ctx->type) {
+ case CACHE_REQ_INITGROUPS:
+ case CACHE_REQ_INITGROUPS_BY_UPN:
+ memcache_type = SSS_MC_INITGROUPS;
+ is_user = true;
+ break;
+ case CACHE_REQ_USER_BY_NAME:
+ case CACHE_REQ_USER_BY_ID:
+ memcache_type = SSS_MC_PASSWD;
+ is_user = true;
+ break;
+ case CACHE_REQ_GROUP_BY_NAME:
+ case CACHE_REQ_GROUP_BY_ID:
+ memcache_type = SSS_MC_GROUP;
+ is_user = false;
+ break;
+ default:
+ /* nothing to do */
+ return EOK;
+ }
+
+ /* Find output name to invalidate memory cache entry*/
+ name = sss_get_name_from_msg(result->domain, result->msgs[0]);
+ if (name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Found object has no name.\n");
+ return EINVAL;
+ }
+ ret = sss_output_fqname(cmd_ctx, result->domain, name,
+ cmd_ctx->nss_ctx->rctx->override_space,
+ &output_name);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sss_output_fqname failed.\n");
+ return ret;
+ }
+
+ memcache_delete_entry(cmd_ctx->nss_ctx, cmd_ctx->nss_ctx->rctx, NULL,
+ output_name, 0, memcache_type);
+ if (memcache_type == SSS_MC_INITGROUPS) {
+ /* Invalidate the passwd data as well */
+ memcache_delete_entry(cmd_ctx->nss_ctx, cmd_ctx->nss_ctx->rctx,
+ result->domain, output_name, 0, SSS_MC_PASSWD);
+ }
+ talloc_free(output_name);
+
+ /* Use sysdb name to invalidate disk cache entry */
+ name = ldb_msg_find_attr_as_string(result->msgs[0], SYSDB_NAME, NULL);
+ if (name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Found object has no name.\n");
+ return EINVAL;
+ }
+
+ if (memcache_type == SSS_MC_INITGROUPS) {
+ attrs = sysdb_new_attrs(cmd_ctx);
+ if (attrs == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n");
+ return ENOMEM;
+ }
+
+ ret = sysdb_attrs_add_time_t(attrs, SYSDB_INITGR_EXPIRE, 1);
+ if (ret != EOK) {
+ talloc_free(attrs);
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_time_t failed.\n");
+ return ret;
+ }
+
+ ret = sysdb_set_user_attr(result->domain, name, attrs, SYSDB_MOD_REP);
+ talloc_free(attrs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_set_user_attr failed.\n");
+ return ret;
+ }
+ }
+
+ ret = sysdb_invalidate_cache_entry(result->domain, name, is_user);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_invalidate_cache_entry failed.\n");
+ return ret;
+ }
+
+ return EOK;
+}
+
static void nss_getby_done(struct tevent_req *subreq)
{
struct cache_req_result *result;
@@ -440,6 +555,16 @@ static void nss_getby_done(struct tevent_req *subreq)
goto done;
}
+ if ((cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) {
+ ret = invalidate_cache(cmd_ctx, result);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to invalidate cache for [%s].\n",
+ cmd_ctx->rawname);
+ nss_protocol_done(cmd_ctx->cli_ctx, ret);
+ goto done;
+ }
+ }
+
nss_protocol_reply(cmd_ctx->cli_ctx, cmd_ctx->nss_ctx, cmd_ctx,
result, cmd_ctx->fill_fn);
diff --git a/src/responder/nss/nss_protocol.c b/src/responder/nss/nss_protocol.c
index 17bfc4f4e71960a72e9e04622eac95b94a865ec7..2655386498754c46fbb363bdd1f976f9ded6a434 100644
--- a/src/responder/nss/nss_protocol.c
+++ b/src/responder/nss/nss_protocol.c
@@ -233,6 +233,7 @@ nss_protocol_parse_id_ex(struct cli_ctx *cli_ctx, uint32_t *_id,
SAFEALIGN_COPY_UINT32(&flags, body + sizeof(uint32_t), NULL);
*_id = id;
+ *_flags = flags;
return EOK;
}
diff --git a/src/responder/nss/nss_protocol.h b/src/responder/nss/nss_protocol.h
index ca5b040237dc18acdca9a7a3a7a7dbb64265aa95..76724d2b2db7b11c9147fa927e39abab731328b2 100644
--- a/src/responder/nss/nss_protocol.h
+++ b/src/responder/nss/nss_protocol.h
@@ -50,6 +50,7 @@ struct nss_cmd_ctx {
struct nss_ctx *nss_ctx;
struct nss_state_ctx *state_ctx;
nss_protocol_fill_packet_fn fill_fn;
+ uint32_t flags;
/* For initgroups- */
const char *rawname;
diff --git a/src/responder/nss/nss_protocol_grent.c b/src/responder/nss/nss_protocol_grent.c
index ee228c722a153a1ba7aa8a1b30a1e551108424bb..6f6ae57dd97b000ad3cf174b0f649d46981563e2 100644
--- a/src/responder/nss/nss_protocol_grent.c
+++ b/src/responder/nss/nss_protocol_grent.c
@@ -274,8 +274,10 @@ nss_protocol_fill_grent(struct nss_ctx *nss_ctx,
num_results++;
- /* Do not store entry in memory cache during enumeration. */
- if (!cmd_ctx->enumeration) {
+ /* Do not store entry in memory cache during enumeration or when
+ * requested. */
+ if (!cmd_ctx->enumeration
+ && (cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) == 0) {
members = (char *)&body[rp_members];
members_size = body_len - rp_members;
ret = sss_mmap_cache_gr_store(&nss_ctx->grp_mc_ctx, name, &pwfield,
@@ -390,7 +392,8 @@ nss_protocol_fill_initgr(struct nss_ctx *nss_ctx,
num_results++;
}
- if (nss_ctx->initgr_mc_ctx) {
+ if (nss_ctx->initgr_mc_ctx
+ && (cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) == 0) {
to_sized_string(&rawname, cmd_ctx->rawname);
to_sized_string(&unique_name, result->lookup_name);
diff --git a/src/responder/nss/nss_protocol_pwent.c b/src/responder/nss/nss_protocol_pwent.c
index db5c071e2ff172a2267c08c9817fecfbcc7cabc3..f449ec69b6a86a6db2aaed368e217c1a791faaa2 100644
--- a/src/responder/nss/nss_protocol_pwent.c
+++ b/src/responder/nss/nss_protocol_pwent.c
@@ -295,8 +295,10 @@ nss_protocol_fill_pwent(struct nss_ctx *nss_ctx,
num_results++;
- /* Do not store entry in memory cache during enumeration. */
- if (!cmd_ctx->enumeration) {
+ /* Do not store entry in memory cache during enumeration or when
+ * requested. */
+ if (!cmd_ctx->enumeration
+ && (cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) == 0) {
ret = sss_mmap_cache_pw_store(&nss_ctx->pwd_mc_ctx, name, &pwfield,
uid, gid, &gecos, &homedir, &shell);
if (ret != EOK) {
diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c
index edb3ea652ef7032b76c8f815b9f83fe185a669ea..148eb7b35ec236b6272dd203a0035399cfdef73d 100644
--- a/src/sss_client/idmap/sss_nss_ex.c
+++ b/src/sss_client/idmap/sss_nss_ex.c
@@ -103,6 +103,18 @@ errno_t sss_nss_mc_get(struct nss_input *inp)
}
}
+static int check_flags(uint32_t flags)
+{
+ /* SSS_NSS_EX_FLAG_NO_CACHE and SSS_NSS_EX_FLAG_INVALIDATE_CACHE are
+ * mutually exclusive */
+ if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0
+ && (flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) {
+ return EINVAL;
+ }
+
+ return 0;
+}
+
int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout)
{
uint8_t *repbuf = NULL;
@@ -117,7 +129,13 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout)
size_t idx;
bool skip_mc = false;
- if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) {
+ ret = check_flags(flags);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0
+ || (flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) {
skip_mc = true;
}
diff --git a/src/sss_client/idmap/sss_nss_idmap.h b/src/sss_client/idmap/sss_nss_idmap.h
index 1649830afbb80c617fd339f054aef8bc8e585fb9..3755643312f05a31d1cf1aa76dfc22848ef1e3ec 100644
--- a/src/sss_client/idmap/sss_nss_idmap.h
+++ b/src/sss_client/idmap/sss_nss_idmap.h
@@ -170,9 +170,15 @@ void sss_nss_free_kv(struct sss_nss_kv *kv_list);
#define SSS_NSS_EX_FLAG_NO_FLAGS 0
/** Always request data from the server side, client must be privileged to do
- * so, see nss_trusted_users option in man sssd.conf for details */
+ * so, see nss_trusted_users option in man sssd.conf for details.
+ * This flag cannot be used together with SSS_NSS_EX_FLAG_INVALIDATE_CACHE */
#define SSS_NSS_EX_FLAG_NO_CACHE (1 << 0)
+/** Invalidate the data in the caches, client must be privileged to do
+ * so, see nss_trusted_users option in man sssd.conf for details.
+ * This flag cannot be used together with SSS_NSS_EX_FLAG_NO_CACHE */
+#define SSS_NSS_EX_FLAG_INVALIDATE_CACHE (1 << 1)
+
#ifdef IPA_389DS_PLUGIN_HELPER_CALLS
/**
--
2.14.3