From cd716b3f95f8532839fcbbce786cded8505e88cf Mon Sep 17 00:00:00 2001
From: Ondrej Kos <okos@redhat.com>
Date: Mon, 20 May 2013 17:37:04 +0200
Subject: [PATCH 2/2] Check NSCD configuration file

https://fedorahosted.org/sssd/ticket/1785

nscd.conf file is now checked for the presence of caching settings for
databases controlled by SSSD. Syslog warning is now written only if NSCD
is running with interfering configuration or if configuration file
couldn't be loaded.

New configure option added to support non-standard locations
--with-nscd-conf=PATH (defaultly set to /etc/nscd.conf)

This is just a workaround until the following bugzilla is resolved:
https://bugzilla.redhat.com/show_bug.cgi?id=963908
---
 Makefile.am           |   3 +-
 configure.ac          |   4 ++
 src/conf_macros.m4    |  14 ++++++
 src/monitor/monitor.c |  32 ++++++++++---
 src/util/nscd.c       | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/util/util.h       |   2 +
 6 files changed, 177 insertions(+), 7 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index c6680521fc311f48ac847942fc463002d34608c0..cfac3061d215940d124519f398e48523208273b7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -617,7 +617,8 @@ include_HEADERS = \
 sssd_SOURCES = \
     src/monitor/monitor.c \
     src/monitor/monitor_netlink.c \
-    src/confdb/confdb_setup.c
+    src/confdb/confdb_setup.c \
+    src/util/nscd.c
 sssd_LDADD = \
     $(SSSD_LIBS) \
     $(LIBNL_LIBS) \
diff --git a/configure.ac b/configure.ac
index f90d7fee3632df74c843d0aaeb03e59eea3c2fee..e63e678705ee059b984612a6ffab1a10a4f7e7f8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -166,6 +166,10 @@ fi
 
 WITH_LIBNL
 
+if test x$HAVE_NSCD; then
+    WITH_NSCD_CONF
+fi
+
 WITH_INITSCRIPT
 if test x$initscript = xsystemd; then
     WITH_SYSTEMD_UNIT_DIR
diff --git a/src/conf_macros.m4 b/src/conf_macros.m4
index 26eb4acccc4895e961ecc50d490a3cdd5716d085..c72b3dd73d5a3eac76c17d8ce2568088f78cfcb3 100644
--- a/src/conf_macros.m4
+++ b/src/conf_macros.m4
@@ -352,6 +352,20 @@ AC_DEFUN([WITH_NSCD],
     AC_DEFINE_UNQUOTED(HAVE_NSCD, $NSCD_PATH, [flush nscd cache after local domain operations])
   ])
 
+AC_DEFUN([WITH_NSCD_CONF],
+  [ AC_ARG_WITH([nscd_conf],
+                [AC_HELP_STRING([--with-nscd-conf=PATH], [Path to nscd.conf file [/etc/nscd.conf]])
+                ]
+               )
+
+    NSCD_CONF_PATH="/etc/nscd.conf"
+    if test x"$with_nscd_conf" != x; then
+        NSCD_CONF_PATH=$with_nscd_conf
+    fi
+    AC_DEFINE_UNQUOTED([NSCD_CONF_PATH], ["$NSCD_CONF_PATH"], [NSCD configuration file])
+  ])
+
+
 AC_DEFUN([WITH_SEMANAGE],
   [ AC_ARG_WITH([semanage],
                 [AC_HELP_STRING([--with-semanage],
diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
index bd22a951d3b48d0ea367e36f628b07e2783d469a..8882e4dbda5f579ef14e7c10f93d0285f85fb381 100644
--- a/src/monitor/monitor.c
+++ b/src/monitor/monitor.c
@@ -2754,12 +2754,32 @@ int main(int argc, const char *argv[])
     /* Warn if nscd seems to be running */
     ret = check_file(NSCD_SOCKET_PATH, -1, -1, -1, CHECK_SOCK, NULL, false);
     if (ret == EOK) {
-        sss_log(SSS_LOG_NOTICE,
-                "nscd socket was detected.  Nscd caching capabilities "
-                "may conflict with SSSD for users and groups. It is "
-                "recommended not to run nscd in parallel with SSSD, unless "
-                "nscd is configured not to cache the passwd, group and "
-                "netgroup nsswitch maps.");
+        ret = sss_nscd_parse_conf(NSCD_CONF_PATH);
+
+        switch (ret) {
+            case ENOENT:
+                sss_log(SSS_LOG_NOTICE,
+                        "NSCD socket was detected. NSCD caching capabilities "
+                        "may conflict with SSSD for users and groups. It is "
+                        "recommended not to run NSCD in parallel with SSSD, "
+                        "unless NSCD is configured not to cache the passwd, "
+                        "group, netgroup and services nsswitch maps.");
+                break;
+
+            case EEXIST:
+                sss_log(SSS_LOG_NOTICE,
+                        "NSCD socket was detected and seems to be configured "
+                        "to cache some of the databases controlled by "
+                        "SSSD [passwd,group,netgroup,services]. It is "
+                        "recommended not to run NSCD in parallel with SSSD, "
+                        "unless NSCD is configured not to cache these.");
+                break;
+
+            case EOK:
+                DEBUG(SSSDBG_TRACE_FUNC, ("NSCD socket was detected and it "
+                            "seems to be configured not to interfere with "
+                            "SSSD's caching capabilities\n"));
+        }
     }
 
     /* Parse config file, fail if cannot be done */
diff --git a/src/util/nscd.c b/src/util/nscd.c
index b9f2ba88cd8ee208d3edc8bdc5010382517d74f2..2a06394d3b5a78ab65dcf8f40746c372488f6c05 100644
--- a/src/util/nscd.c
+++ b/src/util/nscd.c
@@ -95,3 +95,132 @@ int flush_nscd_cache(enum nscd_db flush_db)
     return EOK;
 }
 #endif
+
+/* NSCD config file parse and check */
+
+static unsigned int sss_nscd_check_service(char* svc_name)
+{
+    struct sss_nscd_db {
+        const char *svc_type_name;
+        unsigned int nscd_service_flag;
+    };
+
+    int i;
+    unsigned int ret = 0;
+    struct sss_nscd_db db[] = {
+        { "passwd",   0x0001 },
+        { "group",    0x0010 },
+        { "netgroup", 0x0100 },
+        { "services", 0x1000 },
+        { NULL,       0   }
+    };
+
+    if (svc_name == NULL) {
+        return ret;
+    }
+
+    for (i = 0; db[i].svc_type_name != NULL; i++) {
+        if (!strcmp(db[i].svc_type_name, svc_name)) {
+
+            ret = db[i].nscd_service_flag;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+errno_t sss_nscd_parse_conf(const char *conf_path)
+{
+    FILE *fp;
+    int ret = EOK;
+    unsigned int occured = 0;
+    char *line, *entry, *service, *enabled, *pad;
+    size_t linelen = 0;
+
+    fp = fopen(conf_path, "r");
+    if (fp == NULL) {
+        DEBUG(SSSDBG_MINOR_FAILURE, ("Couldn't open NSCD configuration "
+                    "file [%s]\n", NSCD_CONF_PATH));
+        return ENOENT;
+    }
+
+    while (getline(&line, &linelen, fp) != -1) {
+
+        entry = NULL;
+        service = NULL;
+        enabled = NULL;
+
+        pad = strchr(line, '#');
+        if (pad != NULL) {
+            *pad = '\0';
+        }
+
+        if (line[0] == '\n' || line[0] == '\0') continue;
+
+        entry = line;
+        while (isspace(*entry) && *entry != '\0') {
+            entry++;
+        }
+
+        pad = entry;
+        while (!isspace(*pad) && *pad != '\0') {
+            pad++;
+        }
+
+        service = pad;
+        while (isspace(*service) && *service != '\0') {
+            service++;
+        }
+
+        *pad = '\0';
+        pad = service;
+        while (!isspace(*pad) && *pad != '\0') {
+            pad++;
+        }
+
+        enabled = pad;
+        while (isspace(*enabled) && *enabled != '\0') {
+            enabled++;
+        }
+
+        *pad = '\0';
+        pad = enabled;
+        while (!isspace(*pad) && *pad != '\0') {
+            pad++;
+        }
+        *pad = '\0';
+
+        if (entry   != NULL &&
+            service != NULL &&
+            enabled != NULL) {
+
+            if (!strcmp(entry, "enable-cache") &&
+                !strcmp(enabled, "yes")) {
+
+                occured |= sss_nscd_check_service(service);
+            }
+        }
+    };
+
+    ret = ferror(fp);
+    if (ret) {
+        DEBUG(SSSDBG_MINOR_FAILURE, ("Reading NSCD configuration file [%s] "
+              "ended with failure [%d]: %s.\n",
+              NSCD_CONF_PATH, ret, strerror(ret)));
+        ret = ENOENT;
+        goto done;
+    }
+
+    ret = EOK;
+    if (occured != 0) {
+        ret = EEXIST;
+        goto done;
+    }
+
+done:
+    free(line);
+    fclose(fp);
+
+    return ret;
+}
diff --git a/src/util/util.h b/src/util/util.h
index 566530387285e87d4f79dd36f625d5799c65de30..bdb04a8f3f6cf565743edded84fd798043cbe286 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -499,6 +499,8 @@ enum nscd_db {
 
 int flush_nscd_cache(enum nscd_db flush_db);
 
+errno_t sss_nscd_parse_conf(const char *conf_path);
+
 /* from sss_tc_utf8.c */
 char *
 sss_tc_utf8_str_tolower(TALLOC_CTX *mem_ctx, const char *s);
-- 
1.8.1.4

