>From 4eea31b1fbfbd30b6365a1f2f901a7a7dc76817a Mon Sep 17 00:00:00 2001
From: Michal Zidek <mzidek@redhat.com>
Date: Tue, 11 Sep 2012 18:44:52 +0200
Subject: [PATCH 2/2] sss_cache tool invalidates records in memory cache.

---
 src/monitor/monitor.c                 | 50 +++++++++++++++++++++++++++++--
 src/monitor/monitor_interfaces.h      |  1 +
 src/responder/nss/nsssrv.c            | 50 +++++++++++++++++++++++++++++--
 src/responder/nss/nsssrv_mmap_cache.c | 56 +++++++++++++++++++++++++++++++++++
 src/responder/nss/nsssrv_mmap_cache.h |  5 ++++
 src/tools/sss_cache.c                 | 26 ++++++++++++++++
 src/util/server.c                     | 12 ++++----
 src/util/util.h                       |  2 ++
 8 files changed, 192 insertions(+), 10 deletions(-)

diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
index 1513747..049ec0d 100644
--- a/src/monitor/monitor.c
+++ b/src/monitor/monitor.c
@@ -51,6 +51,7 @@
 #include "dbus/dbus.h"
 #include "sbus/sssd_dbus.h"
 #include "monitor/monitor_interfaces.h"
+#include "responder/nss/nsssrv.h"
 
 #ifdef USE_KEYRING
 #include <keyutils.h>
@@ -701,6 +702,10 @@ static int service_signal_rotate(struct mt_svc *svc)
 {
     return service_signal(svc, MON_CLI_METHOD_ROTATE);
 }
+static int service_signal_clear_memcache(struct mt_svc *svc)
+{
+    return service_signal(svc, MON_CLI_METHOD_CLEAR_MEMCACHE);
+}
 
 static int check_domain_ranges(struct sss_domain_info *domains)
 {
@@ -1174,12 +1179,51 @@ static void monitor_hup(struct tevent_context *ev,
 {
     struct mt_ctx *ctx = talloc_get_type(private_data, struct mt_ctx);
     struct mt_svc *cur_svc;
+    struct stat clear_flag_stat;
+    errno_t ret;
 
     DEBUG(1, ("Received SIGHUP.\n"));
 
-    /* Signal all services to rotate debug files */
-    for(cur_svc = ctx->svc_list; cur_svc; cur_svc = cur_svc->next) {
-        service_signal_rotate(cur_svc);
+    ret = stat(SSS_NSS_MCACHE_DIR"/"CLEAR_MC_FLAG, &clear_flag_stat);
+    if (ret != 0) {
+        ret = errno;
+        if (ret != ENOENT) {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to stat file.\n"));
+            return;
+        }
+    }
+
+    if (ret == ENOENT) {
+        /* Rotate debug files and signal other services to do it too. */
+        DEBUG(SSSDBG_TRACE_FUNC, ("Rotating log files.\n"));
+
+        ret = monitor_common_rotate_logs(ctx->cdb, ctx->conf_path);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_FATAL_FAILURE, ("Could not reopen log file [%s]\n",
+                                         strerror(ret)));
+        }
+
+        for(cur_svc = ctx->svc_list; cur_svc; cur_svc = cur_svc->next) {
+            service_signal_rotate(cur_svc);
+        }
+    } else {
+        /* Signal NSS service to clear memory cache */
+        /* The CLEAR_MC_FLAG_FILE will be removed in sss_mmap_cache_init */
+        DEBUG(SSSDBG_TRACE_FUNC,
+              ("Signal NSS service to clear memory cache.\n"));
+
+        for (cur_svc = ctx->svc_list; cur_svc; cur_svc = cur_svc->next) {
+            if (!strcmp(NSS_SBUS_SERVICE_NAME, cur_svc->name)) {
+                break;
+            }
+        }
+
+        if (!cur_svc) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  ("NSS service not found in service list"));
+        } else {
+            service_signal_clear_memcache(cur_svc);
+        }
     }
 }
 
diff --git a/src/monitor/monitor_interfaces.h b/src/monitor/monitor_interfaces.h
index 51ac254..abe9050 100644
--- a/src/monitor/monitor_interfaces.h
+++ b/src/monitor/monitor_interfaces.h
@@ -45,6 +45,7 @@
 #define MON_CLI_METHOD_OFFLINE "goOffline" /* Applicable only to providers */
 #define MON_CLI_METHOD_RESET_OFFLINE "resetOffline" /* Applicable only to providers */
 #define MON_CLI_METHOD_ROTATE "rotateLogs"
+#define MON_CLI_METHOD_CLEAR_MEMCACHE "clearMemcache"
 
 #define SSSD_SERVICE_PIPE "private/sbus-monitor"
 
diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c
index 64267e8..c1b03ab 100644
--- a/src/responder/nss/nsssrv.c
+++ b/src/responder/nss/nsssrv.c
@@ -51,10 +51,14 @@
 #define SHELL_REALLOC_INCREMENT 5
 #define SHELL_REALLOC_MAX       50
 
+static int nss_clear_memcache(DBusMessage *message,
+                   struct sbus_connection *conn);
+
 struct sbus_method monitor_nss_methods[] = {
     { MON_CLI_METHOD_PING, monitor_common_pong },
     { MON_CLI_METHOD_RES_INIT, monitor_common_res_init },
     { MON_CLI_METHOD_ROTATE, responder_logrotate },
+    { MON_CLI_METHOD_CLEAR_MEMCACHE, nss_clear_memcache},
     { NULL, NULL }
 };
 
@@ -66,6 +70,48 @@ struct sbus_interface monitor_nss_interface = {
     NULL
 };
 
+static int nss_clear_memcache(DBusMessage *message,
+                   struct sbus_connection *conn)
+{
+    errno_t ret;
+    int memcache_timeout;
+    struct resp_ctx *rctx = talloc_get_type(sbus_conn_get_private_data(conn),
+                                            struct resp_ctx);
+    struct nss_ctx *nctx = (struct nss_ctx*)rctx->pvt_ctx;
+
+    ret = confdb_get_int(rctx->cdb,
+                     CONFDB_NSS_CONF_ENTRY,
+                     CONFDB_MEMCACHE_TIMEOUT,
+                     300, &memcache_timeout);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE,
+              ("Unable to get memory cache entry timeout.\n"));
+        return ret;
+    }
+
+    /* TODO: read cache sizes from configuration */
+    DEBUG(SSSDBG_TRACE_FUNC, ("Clearing memory caches.\n"));
+    ret = sss_mmap_cache_reinit(nctx, SSS_MC_CACHE_ELEMENTS,
+                                (time_t)memcache_timeout,
+                                &nctx->pwd_mc_ctx);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              ("passwd mmap cache invalidation failed\n"));
+        return ret;
+    }
+
+    ret = sss_mmap_cache_reinit(nctx, SSS_MC_CACHE_ELEMENTS,
+                                (time_t)memcache_timeout,
+                                &nctx->grp_mc_ctx);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              ("group mmap cache invalidation failed\n"));
+        return ret;
+    }
+
+    return monitor_common_pong(message, conn);
+}
+
 static errno_t nss_get_etc_shells(TALLOC_CTX *mem_ctx, char ***_shells)
 {
     int i = 0;
@@ -339,14 +385,14 @@ int nss_process_init(TALLOC_CTX *mem_ctx,
 
     /* TODO: read cache sizes from configuration */
     ret = sss_mmap_cache_init(nctx, "passwd", SSS_MC_PASSWD,
-                              50000, (time_t)memcache_timeout,
+                              SSS_MC_CACHE_ELEMENTS, (time_t)memcache_timeout,
                               &nctx->pwd_mc_ctx);
     if (ret) {
         DEBUG(SSSDBG_CRIT_FAILURE, ("passwd mmap cache is DISABLED\n"));
     }
 
     ret = sss_mmap_cache_init(nctx, "group", SSS_MC_GROUP,
-                              50000, (time_t)memcache_timeout,
+                              SSS_MC_CACHE_ELEMENTS, (time_t)memcache_timeout,
                               &nctx->grp_mc_ctx);
     if (ret) {
         DEBUG(SSSDBG_CRIT_FAILURE, ("group mmap cache is DISABLED\n"));
diff --git a/src/responder/nss/nsssrv_mmap_cache.c b/src/responder/nss/nsssrv_mmap_cache.c
index 07498a9..51579e8 100644
--- a/src/responder/nss/nsssrv_mmap_cache.c
+++ b/src/responder/nss/nsssrv_mmap_cache.c
@@ -609,6 +609,14 @@ errno_t sss_mmap_cache_init(TALLOC_CTX *mem_ctx, const char *name,
     int payload;
     int ret;
 
+    ret = unlink(SSS_NSS_MCACHE_DIR"/"CLEAR_MC_FLAG);
+    if (ret != 0 && errno != ENOENT) {
+        ret = errno;
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to unlink file: %s.\n",
+              strerror(ret)));
+        return ret;
+    }
+
     switch (type) {
     case SSS_MC_PASSWD:
         payload = SSS_AVG_PASSWD_PAYLOAD;
@@ -725,3 +733,51 @@ done:
     return ret;
 }
 
+errno_t sss_mmap_cache_reinit(TALLOC_CTX *mem_ctx, size_t n_elem,
+                              time_t timeout, struct sss_mc_ctx **mc_ctx)
+{
+    errno_t ret;
+    TALLOC_CTX* local_ctx;
+    char *name;
+    enum sss_mc_type type;
+
+    if (mc_ctx == NULL || (*mc_ctx) == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              ("Unable to re-init unitialized memory cache.\n"));
+        return EINVAL;
+    }
+
+    local_ctx = talloc_new(mem_ctx);
+    if (local_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory.\n"));
+        return ENOMEM;
+    }
+
+    name = talloc_strdup(local_ctx, (*mc_ctx)->name);
+    if (name == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory.\n"));
+        ret = ENOMEM;
+        goto done;
+    }
+
+    type = (*mc_ctx)->type;
+    ret = talloc_free(*mc_ctx);
+    if (ret != 0) {
+        /* This can happen only if destructor is associated with this
+         * context */
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Destructor asociated with memory"
+                                    " context failed.\n"));
+        goto done;
+    }
+
+    ret = sss_mmap_cache_init(mem_ctx, name, type, n_elem, timeout, mc_ctx);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to re-initialize mmap cache.\n"));
+        goto done;
+    }
+
+done:
+    talloc_free(local_ctx);
+    return ret;
+}
+
diff --git a/src/responder/nss/nsssrv_mmap_cache.h b/src/responder/nss/nsssrv_mmap_cache.h
index 81241b2..2a0712c 100644
--- a/src/responder/nss/nsssrv_mmap_cache.h
+++ b/src/responder/nss/nsssrv_mmap_cache.h
@@ -22,6 +22,8 @@
 #ifndef _NSSSRV_MMAP_CACHE_H_
 #define _NSSSRV_MMAP_CACHE_H_
 
+#define SSS_MC_CACHE_ELEMENTS 50000
+
 struct sss_mc_ctx;
 
 enum sss_mc_type {
@@ -48,4 +50,7 @@ errno_t sss_mmap_cache_gr_store(struct sss_mc_ctx *mcc,
                                 gid_t gid, size_t memnum,
                                 char *membuf, size_t memsize);
 
+errno_t sss_mmap_cache_reinit(TALLOC_CTX *mem_ctx, size_t n_elem,
+                              time_t timeout, struct sss_mc_ctx **mc_ctx);
+
 #endif /* _NSSSRV_MMAP_CACHE_H_ */
diff --git a/src/tools/sss_cache.c b/src/tools/sss_cache.c
index 950ff1c..73d9965 100644
--- a/src/tools/sss_cache.c
+++ b/src/tools/sss_cache.c
@@ -100,6 +100,7 @@ int main(int argc, const char *argv[])
     struct sysdb_ctx *sysdb;
     int i;
     bool skipped;
+    FILE *clear_mc_flag;
 
     ret = init_context(argc, argv, &tctx);
     if (ret != EOK) {
@@ -141,6 +142,31 @@ int main(int argc, const char *argv[])
             ERROR("No cache object matched the specified search\n");
             ret = ENOENT;
             goto done;
+        } else {
+            /*Local cache changed -> signal monitor to invalidate fastcache */
+            clear_mc_flag = fopen(SSS_NSS_MCACHE_DIR"/"CLEAR_MC_FLAG, "w");
+            if (clear_mc_flag == NULL) {
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                      ("Failed to create clear_mc_flag file. "
+                      "Memory cache will not be cleared.\n"));
+                goto done;
+            }
+            ret = fclose(clear_mc_flag);
+            if (ret != 0) {
+                ret = errno;
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                      ("Unable to close file descriptor: %s\n",
+                       strerror(ret)));
+                goto done;
+            }
+
+            DEBUG(SSSDBG_TRACE_FUNC, ("Sending SIGHUP to monitor.\n"));
+            ret = signal_sssd(SIGHUP);
+            if (ret != EOK) {
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                      ("Failed to send SIGHUP to monitor.\n"));
+                goto done;
+            }
         }
     }
 
diff --git a/src/util/server.c b/src/util/server.c
index f3f1b20..e208fdc 100644
--- a/src/util/server.c
+++ b/src/util/server.c
@@ -508,12 +508,14 @@ int server_setup(const char *name, int flags,
     lctx->confdb = ctx->confdb_ctx;
     lctx->confdb_path = conf_entry;
 
-    tes = tevent_add_signal(ctx->event_ctx, ctx, SIGHUP, 0,
-                            te_server_hup, lctx);
-    if (tes == NULL) {
-        return EIO;
+    /* Do not set SIGHUP handler for monitor */
+    if (strcmp(name, "sssd")) {
+        tes = tevent_add_signal(ctx->event_ctx, ctx, SIGHUP, 0,
+                                te_server_hup, lctx);
+        if (tes == NULL) {
+            return EIO;
+        }
     }
-
     /* open log file if told so */
     if (debug_to_file) {
         ret = open_debug_file();
diff --git a/src/util/util.h b/src/util/util.h
index 685702f..df739ab 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -54,6 +54,8 @@ typedef int errno_t;
 
 #define ENUM_INDICATOR "*"
 
+#define CLEAR_MC_FLAG "clear_mc_flag"
+
 extern const char *debug_prg_name;
 extern int debug_level;
 extern int debug_timestamps;
-- 
1.7.11.2

