Blame SOURCES/0028-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch

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