From 34f79fb7f7fa0e6246ec06b8dcd428ade48a8f4e Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Thu, 11 Mar 2010 18:10:15 +0100
Subject: [PATCH] Flush NSCD cache after modifying local database

Fixes: #221
---
 src/Makefile.am          |    3 +-
 src/configure.ac         |    1 +
 src/external/nscd.m4     |    9 +++++
 src/python/pysss.c       |   15 ++++++++
 src/tools/nscd.c         |   89 ++++++++++++++++++++++++++++++++++++++++++++++
 src/tools/sss_groupadd.c |    8 ++++
 src/tools/sss_groupdel.c |    8 ++++
 src/tools/sss_groupmod.c |    8 ++++
 src/tools/sss_useradd.c  |   15 ++++++++
 src/tools/sss_userdel.c  |   15 ++++++++
 src/tools/sss_usermod.c  |   15 ++++++++
 src/tools/tools_util.h   |    8 ++++
 12 files changed, 193 insertions(+), 1 deletions(-)
 create mode 100644 src/external/nscd.m4
 create mode 100644 src/tools/nscd.c

diff --git a/src/Makefile.am b/src/Makefile.am
index 9da383b..75e1cab 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -246,7 +246,8 @@ SSSD_RESPONDER_OBJ = \
 SSSD_TOOLS_OBJ = \
     tools/sss_sync_ops.c \
     tools/tools_util.c \
-    tools/files.c
+    tools/files.c \
+    tools/nscd.c
 
 SSSD_RESOLV_OBJ = \
     resolv/async_resolv.c
diff --git a/src/configure.ac b/src/configure.ac
index d7a7a77..e112fce 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -92,6 +92,7 @@ m4_include([external/sizes.m4])
 m4_include([external/python.m4])
 m4_include([external/selinux.m4])
 m4_include([external/crypto.m4])
+m4_include([external/nscd.m4])
 m4_include([util/signal.m4])
 
 PKG_CHECK_MODULES([DBUS],[dbus-1])
diff --git a/src/external/nscd.m4 b/src/external/nscd.m4
new file mode 100644
index 0000000..f9f54c5
--- /dev/null
+++ b/src/external/nscd.m4
@@ -0,0 +1,9 @@
+AC_PATH_PROG(NSCD, nscd)
+AC_MSG_CHECKING(for nscd)
+if test -x "$NSCD"; then
+  AC_DEFINE_UNQUOTED([NSCD_PATH], "$NSCD", [The path to nscd, if available])
+  AC_MSG_RESULT(yes)
+else
+  AC_MSG_RESULT(no. Manipulating nscd cache will not be available.)
+fi
+
diff --git a/src/python/pysss.c b/src/python/pysss.c
index 8011ed6..3d35c6b 100644
--- a/src/python/pysss.c
+++ b/src/python/pysss.c
@@ -298,6 +298,9 @@ static PyObject *py_sss_useradd(PySssLocalObject *self,
                           tctx->octx->gid);
     }
 
+    flush_nscd_cache(tctx, NSCD_DB_PASSWD);
+    flush_nscd_cache(tctx, NSCD_DB_GROUP);
+
     talloc_zfree(tctx);
     Py_RETURN_NONE;
 
@@ -416,6 +419,9 @@ static PyObject *py_sss_userdel(PySssLocalObject *self,
         }
     }
 
+    flush_nscd_cache(tctx, NSCD_DB_PASSWD);
+    flush_nscd_cache(tctx, NSCD_DB_GROUP);
+
     talloc_zfree(tctx);
     Py_RETURN_NONE;
 
@@ -541,6 +547,9 @@ static PyObject *py_sss_usermod(PySssLocalObject *self,
         goto fail;
     }
 
+    flush_nscd_cache(tctx, NSCD_DB_PASSWD);
+    flush_nscd_cache(tctx, NSCD_DB_GROUP);
+
     talloc_zfree(tctx);
     Py_RETURN_NONE;
 
@@ -612,6 +621,8 @@ static PyObject *py_sss_groupadd(PySssLocalObject *self,
         goto fail;
     }
 
+    flush_nscd_cache(tctx, NSCD_DB_GROUP);
+
     talloc_zfree(tctx);
     Py_RETURN_NONE;
 
@@ -672,6 +683,8 @@ static PyObject *py_sss_groupdel(PySssLocalObject *self,
         goto fail;
     }
 
+    flush_nscd_cache(tctx, NSCD_DB_GROUP);
+
     talloc_zfree(tctx);
     Py_RETURN_NONE;
 
@@ -770,6 +783,8 @@ static PyObject *py_sss_groupmod(PySssLocalObject *self,
         goto fail;
     }
 
+    flush_nscd_cache(tctx, NSCD_DB_GROUP);
+
     talloc_zfree(tctx);
     Py_RETURN_NONE;
 
diff --git a/src/tools/nscd.c b/src/tools/nscd.c
new file mode 100644
index 0000000..c51fe03
--- /dev/null
+++ b/src/tools/nscd.c
@@ -0,0 +1,89 @@
+/*
+   SSSD
+
+   nscd.c
+
+   Copyright (C) Jakub Hrozek <jhrozek@redhat.com>        2010
+
+   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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <talloc.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "config.h"
+#include "util/util.h"
+#include "tools/tools_util.h"
+
+#ifndef NSCD_RELOAD_ARG
+#define NSCD_RELOAD_ARG "-i"
+#endif
+
+#ifdef NSCD_PATH
+int flush_nscd_cache(TALLOC_CTX *mem_ctx, enum nscd_db flush_db)
+{
+    char *cmd = NULL;
+    const char *service;
+    int ret;
+
+    switch(flush_db) {
+        case NSCD_DB_PASSWD:
+            service = "passwd";
+            break;
+
+        case NSCD_DB_GROUP:
+            service = "group";
+            break;
+
+        default:
+            DEBUG(1, ("Unknown nscd database\n"));
+            ret = EINVAL;
+            goto done;
+    }
+
+    cmd = talloc_asprintf(mem_ctx, "%s %s %s", NSCD_PATH,
+                                               NSCD_RELOAD_ARG,
+                                               service);
+    if (!cmd) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = system(cmd);
+    if (ret) {
+        if (ret == -1) {
+            DEBUG(1, ("system(3) failed\n"));
+            ret = EFAULT;
+            goto done;
+        }
+        /* The flush fails if nscd is not running, so do not care
+         * about the return code */
+        DEBUG(8, ("Error flushing cache, perhaps nscd is not running\n"));
+    }
+
+
+    ret = EOK;
+done:
+    talloc_free(cmd);
+    return ret;
+}
+
+#else   /* NSCD_PATH */
+int flush_nscd_cache(TALLOC_CTX *mem_ctx, enum nscd_db flush_db)
+{
+    return EOK;
+}
+#endif
diff --git a/src/tools/sss_groupadd.c b/src/tools/sss_groupadd.c
index 15eed10..103cf26 100644
--- a/src/tools/sss_groupadd.c
+++ b/src/tools/sss_groupadd.c
@@ -125,6 +125,14 @@ int main(int argc, const char **argv)
 
     end_transaction(tctx);
 
+    ret = flush_nscd_cache(tctx, NSCD_DB_GROUP);
+    if (ret != EOK) {
+        ERROR("Cannot flush nscd cache\n");
+        DEBUG(1, ("Cannot flush nscd group cache: [%d][%s].\n",
+                  ret, strerror(ret)));
+        /* Should not be fatal */
+    }
+
 done:
     if (tctx->error) {
         ret = tctx->error;
diff --git a/src/tools/sss_groupdel.c b/src/tools/sss_groupdel.c
index e5b043e..aac12f8 100644
--- a/src/tools/sss_groupdel.c
+++ b/src/tools/sss_groupdel.c
@@ -127,6 +127,14 @@ int main(int argc, const char **argv)
 
     end_transaction(tctx);
 
+    ret = flush_nscd_cache(tctx, NSCD_DB_GROUP);
+    if (ret != EOK) {
+        ERROR("Cannot flush nscd cache\n");
+        DEBUG(1, ("Cannot flush nscd group cache: [%d][%s].\n",
+                  ret, strerror(ret)));
+        /* Should not be fatal */
+    }
+
     ret = tctx->error;
 done:
     if (ret) {
diff --git a/src/tools/sss_groupmod.c b/src/tools/sss_groupmod.c
index b25a018..b0980bf 100644
--- a/src/tools/sss_groupmod.c
+++ b/src/tools/sss_groupmod.c
@@ -213,6 +213,14 @@ int main(int argc, const char **argv)
 
     end_transaction(tctx);
 
+    ret = flush_nscd_cache(tctx, NSCD_DB_GROUP);
+    if (ret != EOK) {
+        ERROR("Cannot flush nscd cache\n");
+        DEBUG(1, ("Cannot flush nscd group cache: [%d][%s].\n",
+                  ret, strerror(ret)));
+        /* Should not be fatal */
+    }
+
 done:
     if (tctx->error) {
         ret = tctx->error;
diff --git a/src/tools/sss_useradd.c b/src/tools/sss_useradd.c
index 077ac99..7473829 100644
--- a/src/tools/sss_useradd.c
+++ b/src/tools/sss_useradd.c
@@ -318,6 +318,21 @@ int main(int argc, const char **argv)
         }
     }
 
+    ret = flush_nscd_cache(tctx, NSCD_DB_PASSWD);
+    if (ret != EOK) {
+        ERROR("Cannot flush nscd cache\n");
+        DEBUG(1, ("Cannot flush nscd user cache: [%d][%s].\n",
+                  ret, strerror(ret)));
+        /* Should not be fatal */
+    }
+    ret = flush_nscd_cache(tctx, NSCD_DB_GROUP);
+    if (ret != EOK) {
+        ERROR("Cannot flush nscd cache\n");
+        DEBUG(1, ("Cannot flush nscd group cache: [%d][%s].\n",
+                  ret, strerror(ret)));
+        /* Should not be fatal */
+    }
+
 done:
     if (tctx->error) {
         switch (tctx->error) {
diff --git a/src/tools/sss_userdel.c b/src/tools/sss_userdel.c
index e84d78b..b70dc5c 100644
--- a/src/tools/sss_userdel.c
+++ b/src/tools/sss_userdel.c
@@ -177,6 +177,21 @@ int main(int argc, const char **argv)
         }
     }
 
+    ret = flush_nscd_cache(tctx, NSCD_DB_PASSWD);
+    if (ret != EOK) {
+        ERROR("Cannot flush nscd cache\n");
+        DEBUG(1, ("Cannot flush nscd user cache: [%d][%s].\n",
+                  ret, strerror(ret)));
+        /* Should not be fatal */
+    }
+    ret = flush_nscd_cache(tctx, NSCD_DB_GROUP);
+    if (ret != EOK) {
+        ERROR("Cannot flush nscd cache\n");
+        DEBUG(1, ("Cannot flush nscd group cache: [%d][%s].\n",
+                  ret, strerror(ret)));
+        /* Should not be fatal */
+    }
+
     ret = tctx->error;
 done:
     if (ret) {
diff --git a/src/tools/sss_usermod.c b/src/tools/sss_usermod.c
index a272bc5..75d2033 100644
--- a/src/tools/sss_usermod.c
+++ b/src/tools/sss_usermod.c
@@ -233,6 +233,21 @@ int main(int argc, const char **argv)
 
     end_transaction(tctx);
 
+    ret = flush_nscd_cache(tctx, NSCD_DB_PASSWD);
+    if (ret != EOK) {
+        ERROR("Cannot flush nscd cache\n");
+        DEBUG(1, ("Cannot flush nscd user cache: [%d][%s].\n",
+                  ret, strerror(ret)));
+        /* Should not be fatal */
+    }
+    ret = flush_nscd_cache(tctx, NSCD_DB_GROUP);
+    if (ret != EOK) {
+        ERROR("Cannot flush nscd cache\n");
+        DEBUG(1, ("Cannot flush nscd group cache: [%d][%s].\n",
+                  ret, strerror(ret)));
+        /* Should not be fatal */
+    }
+
 done:
     if (tctx->error) {
         ret = tctx->error;
diff --git a/src/tools/tools_util.h b/src/tools/tools_util.h
index a643e73..a2b5c78 100644
--- a/src/tools/tools_util.h
+++ b/src/tools/tools_util.h
@@ -105,4 +105,12 @@ int copy_tree(const char *src_root,
 int selinux_file_context(const char *dst_name);
 int reset_selinux_file_context(void);
 
+/* from nscd.c */
+enum nscd_db {
+    NSCD_DB_PASSWD,
+    NSCD_DB_GROUP
+};
+
+int flush_nscd_cache(TALLOC_CTX *mem_ctx, enum nscd_db flush_db);
+
 #endif  /* __TOOLS_UTIL_H__ */
-- 
1.6.6.1

