Blob Blame History Raw
From 4aaf05d72e9d6daf348cefb8a6ad35d2966cbe9b Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jakub.hrozek@posteo.se>
Date: Wed, 12 Sep 2018 14:22:11 +0200
Subject: [PATCH] Flush sssd caches in addition to nscd caches

Some distributions, notably Fedora, have the following order of nsswitch
modules by default:
    passwd: sss files
    group:  sss files

The advantage of serving local users through SSSD is that the nss_sss
module has a fast mmapped-cache that speeds up NSS lookups compared to
accessing the disk an opening the files on each NSS request.

Traditionally, this has been done with the help of nscd, but using nscd
in parallel with sssd is cumbersome, as both SSSD and nscd use their own
independent caching, so using nscd in setups where sssd is also serving
users from some remote domain (LDAP, AD, ...) can result in a bit of
unpredictability.

More details about why Fedora chose to use sss before files can be found
on e.g.:
    https://fedoraproject.org//wiki/Changes/SSSDCacheForLocalUsers
or:
    https://docs.pagure.org/SSSD.sssd/design_pages/files_provider.html

Now, even though sssd watches the passwd and group files with the help
of inotify, there can still be a small window where someone requests a
user or a group, finds that it doesn't exist, adds the entry and checks
again. Without some support in shadow-utils that would explicitly drop
the sssd caches, the inotify watch can fire a little late, so a
combination of commands like this:
    getent passwd user || useradd user; getent passwd user
can result in the second getent passwd not finding the newly added user
as the racy behaviour might still return the cached negative hit from
the first getent passwd.

This patch more or less copies the already existing support that
shadow-utils had for dropping nscd caches, except using the "sss_cache"
tool that sssd ships.
---
 configure.ac    | 10 +++++++
 lib/Makefile.am |  2 ++
 lib/commonio.c  |  2 ++
 lib/sssd.c      | 75 +++++++++++++++++++++++++++++++++++++++++++++++++
 lib/sssd.h      | 17 +++++++++++
 src/chfn.c      |  2 ++
 src/chgpasswd.c |  2 ++
 src/chpasswd.c  |  2 ++
 src/chsh.c      |  2 ++
 src/gpasswd.c   |  2 ++
 src/groupadd.c  |  2 ++
 src/groupdel.c  |  2 ++
 src/groupmod.c  |  2 ++
 src/grpck.c     |  2 ++
 src/grpconv.c   |  2 ++
 src/grpunconv.c |  2 ++
 src/newusers.c  |  2 ++
 src/passwd.c    |  2 ++
 src/pwck.c      |  2 ++
 src/pwconv.c    |  2 ++
 src/pwunconv.c  |  2 ++
 src/useradd.c   |  2 ++
 src/userdel.c   |  2 ++
 src/usermod.c   |  2 ++
 src/vipw.c      |  2 ++
 25 files changed, 146 insertions(+)
 create mode 100644 lib/sssd.c
 create mode 100644 lib/sssd.h

diff --git a/configure.ac b/configure.ac
index 41068a5d..10ad70cf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -280,6 +280,9 @@ AC_ARG_WITH(sha-crypt,
 AC_ARG_WITH(nscd,
 	[AC_HELP_STRING([--with-nscd], [enable support for nscd @<:@default=yes@:>@])],
 	[with_nscd=$withval], [with_nscd=yes])
+AC_ARG_WITH(sssd,
+	[AC_HELP_STRING([--with-sssd], [enable support for flushing sssd caches @<:@default=yes@:>@])],
+	[with_sssd=$withval], [with_sssd=yes])
 AC_ARG_WITH(group-name-max-length,
 	[AC_HELP_STRING([--with-group-name-max-length], [set max group name length @<:@default=16@:>@])],
 	[with_group_name_max_length=$withval], [with_group_name_max_length=yes])
@@ -304,6 +307,12 @@ if test "$with_nscd" = "yes"; then
 	              [AC_MSG_ERROR([posix_spawn is needed for nscd support])])
 fi
 
+if test "$with_sssd" = "yes"; then
+	AC_CHECK_FUNC(posix_spawn,
+	              [AC_DEFINE(USE_SSSD, 1, [Define to support flushing of sssd caches])],
+	              [AC_MSG_ERROR([posix_spawn is needed for sssd support])])
+fi
+
 dnl Check for some functions in libc first, only if not found check for
 dnl other libraries.  This should prevent linking libnsl if not really
 dnl needed (Linux glibc, Irix), but still link it if needed (Solaris).
@@ -679,5 +688,6 @@ echo "	shadow group support:		$enable_shadowgrp"
 echo "	S/Key support:			$with_skey"
 echo "	SHA passwords encryption:	$with_sha_crypt"
 echo "	nscd support:			$with_nscd"
+echo "	sssd support:			$with_sssd"
 echo "	subordinate IDs support:	$enable_subids"
 echo
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 6db86cd6..fd634542 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -30,6 +30,8 @@ libshadow_la_SOURCES = \
 	lockpw.c \
 	nscd.c \
 	nscd.h \
+	sssd.c \
+	sssd.h \
 	pam_defs.h \
 	port.c \
 	port.h \
diff --git a/lib/commonio.c b/lib/commonio.c
index d06b8e7d..96f2d5f7 100644
--- a/lib/commonio.c
+++ b/lib/commonio.c
@@ -45,6 +45,7 @@
 #include <stdio.h>
 #include <signal.h>
 #include "nscd.h"
+#include "sssd.h"
 #ifdef WITH_TCB
 #include <tcb.h>
 #endif				/* WITH_TCB */
@@ -485,6 +486,7 @@ static void dec_lock_count (void)
 			if (nscd_need_reload) {
 				nscd_flush_cache ("passwd");
 				nscd_flush_cache ("group");
+				sssd_flush_cache (SSSD_DB_PASSWD | SSSD_DB_GROUP);
 				nscd_need_reload = false;
 			}
 #ifdef HAVE_LCKPWDF
diff --git a/lib/sssd.c b/lib/sssd.c
new file mode 100644
index 00000000..80e49e55
--- /dev/null
+++ b/lib/sssd.c
@@ -0,0 +1,75 @@
+/* Author: Peter Vrabec <pvrabec@redhat.com> */
+
+#include <config.h>
+#ifdef USE_SSSD
+
+#include <stdio.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include "exitcodes.h"
+#include "defines.h"
+#include "prototypes.h"
+#include "sssd.h"
+
+#define MSG_SSSD_FLUSH_CACHE_FAILED "%s: Failed to flush the sssd cache.\n"
+
+int sssd_flush_cache (int dbflags)
+{
+	int status, code, rv;
+	const char *cmd = "/usr/sbin/sss_cache";
+	char *sss_cache_args = NULL;
+	const char *spawnedArgs[] = {"sss_cache", NULL, NULL};
+	const char *spawnedEnv[] = {NULL};
+	int i = 0;
+
+	sss_cache_args = malloc(4);
+	if (sss_cache_args == NULL) {
+	    return -1;
+	}
+
+	sss_cache_args[i++] = '-';
+	if (dbflags & SSSD_DB_PASSWD) {
+		sss_cache_args[i++] = 'U';
+	}
+	if (dbflags & SSSD_DB_GROUP) {
+		sss_cache_args[i++] = 'G';
+	}
+	sss_cache_args[i++] = '\0';
+	if (i == 2) {
+		/* Neither passwd nor group, nothing to do */
+		free(sss_cache_args);
+		return 0;
+	}
+	spawnedArgs[1] = sss_cache_args;
+
+	rv = run_command (cmd, spawnedArgs, spawnedEnv, &status);
+	free(sss_cache_args);
+	if (rv != 0) {
+		/* run_command writes its own more detailed message. */
+		(void) fprintf (stderr, _(MSG_SSSD_FLUSH_CACHE_FAILED), Prog);
+		return -1;
+	}
+
+	code = WEXITSTATUS (status);
+	if (!WIFEXITED (status)) {
+		(void) fprintf (stderr,
+		                _("%s: sss_cache did not terminate normally (signal %d)\n"),
+		                Prog, WTERMSIG (status));
+		return -1;
+	} else if (code == E_CMD_NOTFOUND) {
+		/* sss_cache is not installed, or it is installed but uses an
+		   interpreter that is missing.  Probably the former. */
+		return 0;
+	} else if (code != 0) {
+		(void) fprintf (stderr, _("%s: sss_cache exited with status %d\n"),
+		                Prog, code);
+		(void) fprintf (stderr, _(MSG_SSSD_FLUSH_CACHE_FAILED), Prog);
+		return -1;
+	}
+
+	return 0;
+}
+#else				/* USE_SSSD */
+extern int errno;		/* warning: ANSI C forbids an empty source file */
+#endif				/* USE_SSSD */
+
diff --git a/lib/sssd.h b/lib/sssd.h
new file mode 100644
index 00000000..00ff2a8a
--- /dev/null
+++ b/lib/sssd.h
@@ -0,0 +1,17 @@
+#ifndef _SSSD_H_
+#define _SSSD_H_
+
+#define SSSD_DB_PASSWD	0x001
+#define SSSD_DB_GROUP	0x002
+
+/*
+ * sssd_flush_cache - flush specified service buffer in sssd cache
+ */
+#ifdef	USE_SSSD
+extern int sssd_flush_cache (int dbflags);
+#else
+#define sssd_flush_cache(service) (0)
+#endif
+
+#endif
+
diff --git a/src/chfn.c b/src/chfn.c
index 18aa3de7..0725e1c7 100644
--- a/src/chfn.c
+++ b/src/chfn.c
@@ -47,6 +47,7 @@
 #include "defines.h"
 #include "getdef.h"
 #include "nscd.h"
+#include "sssd.h"
 #ifdef USE_PAM
 #include "pam_defs.h"
 #endif
@@ -746,6 +747,7 @@ int main (int argc, char **argv)
 	SYSLOG ((LOG_INFO, "changed user '%s' information", user));
 
 	nscd_flush_cache ("passwd");
+	sssd_flush_cache (SSSD_DB_PASSWD);
 
 	closelog ();
 	exit (E_SUCCESS);
diff --git a/src/chgpasswd.c b/src/chgpasswd.c
index 13203a46..e5f2eb7e 100644
--- a/src/chgpasswd.c
+++ b/src/chgpasswd.c
@@ -46,6 +46,7 @@
 #endif				/* ACCT_TOOLS_SETUID */
 #include "defines.h"
 #include "nscd.h"
+#include "sssd.h"
 #include "prototypes.h"
 #include "groupio.h"
 #ifdef	SHADOWGRP
@@ -581,6 +582,7 @@ int main (int argc, char **argv)
 	close_files ();
 
 	nscd_flush_cache ("group");
+	sssd_flush_cache (SSSD_DB_GROUP);
 
 	return (0);
 }
diff --git a/src/chpasswd.c b/src/chpasswd.c
index 918b27ee..49e79cdb 100644
--- a/src/chpasswd.c
+++ b/src/chpasswd.c
@@ -44,6 +44,7 @@
 #endif				/* USE_PAM */
 #include "defines.h"
 #include "nscd.h"
+#include "sssd.h"
 #include "getdef.h"
 #include "prototypes.h"
 #include "pwio.h"
@@ -624,6 +625,7 @@ int main (int argc, char **argv)
 	}
 
 	nscd_flush_cache ("passwd");
+	sssd_flush_cache (SSSD_DB_PASSWD);
 
 	return (0);
 }
diff --git a/src/chsh.c b/src/chsh.c
index c89708b9..910e3dd4 100644
--- a/src/chsh.c
+++ b/src/chsh.c
@@ -46,6 +46,7 @@
 #include "defines.h"
 #include "getdef.h"
 #include "nscd.h"
+#include "sssd.h"
 #include "prototypes.h"
 #include "pwauth.h"
 #include "pwio.h"
@@ -557,6 +558,7 @@ int main (int argc, char **argv)
 	SYSLOG ((LOG_INFO, "changed user '%s' shell to '%s'", user, loginsh));
 
 	nscd_flush_cache ("passwd");
+	sssd_flush_cache (SSSD_DB_PASSWD);
 
 	closelog ();
 	exit (E_SUCCESS);
diff --git a/src/gpasswd.c b/src/gpasswd.c
index c4a492b1..4d75af96 100644
--- a/src/gpasswd.c
+++ b/src/gpasswd.c
@@ -45,6 +45,7 @@
 #include "defines.h"
 #include "groupio.h"
 #include "nscd.h"
+#include "sssd.h"
 #include "prototypes.h"
 #ifdef SHADOWGRP
 #include "sgroupio.h"
@@ -1201,6 +1202,7 @@ int main (int argc, char **argv)
 	close_files ();
 
 	nscd_flush_cache ("group");
+	sssd_flush_cache (SSSD_DB_GROUP);
 
 	exit (E_SUCCESS);
 }
diff --git a/src/groupadd.c b/src/groupadd.c
index b57006c5..2dd8eec9 100644
--- a/src/groupadd.c
+++ b/src/groupadd.c
@@ -51,6 +51,7 @@
 #include "getdef.h"
 #include "groupio.h"
 #include "nscd.h"
+#include "sssd.h"
 #include "prototypes.h"
 #ifdef	SHADOWGRP
 #include "sgroupio.h"
@@ -625,6 +626,7 @@ int main (int argc, char **argv)
 	close_files ();
 
 	nscd_flush_cache ("group");
+	sssd_flush_cache (SSSD_DB_GROUP);
 
 	return E_SUCCESS;
 }
diff --git a/src/groupdel.c b/src/groupdel.c
index 70bed010..f941a84a 100644
--- a/src/groupdel.c
+++ b/src/groupdel.c
@@ -49,6 +49,7 @@
 #include "defines.h"
 #include "groupio.h"
 #include "nscd.h"
+#include "sssd.h"
 #include "prototypes.h"
 #ifdef	SHADOWGRP
 #include "sgroupio.h"
@@ -492,6 +493,7 @@ int main (int argc, char **argv)
 	close_files ();
 
 	nscd_flush_cache ("group");
+	sssd_flush_cache (SSSD_DB_GROUP);
 
 	return E_SUCCESS;
 }
diff --git a/src/groupmod.c b/src/groupmod.c
index b293b98f..1dca5fc9 100644
--- a/src/groupmod.c
+++ b/src/groupmod.c
@@ -51,6 +51,7 @@
 #include "groupio.h"
 #include "pwio.h"
 #include "nscd.h"
+#include "sssd.h"
 #include "prototypes.h"
 #ifdef	SHADOWGRP
 #include "sgroupio.h"
@@ -877,6 +878,7 @@ int main (int argc, char **argv)
 	close_files ();
 
 	nscd_flush_cache ("group");
+	sssd_flush_cache (SSSD_DB_GROUP);
 
 	return E_SUCCESS;
 }
diff --git a/src/grpck.c b/src/grpck.c
index ea5d3b39..6140b10d 100644
--- a/src/grpck.c
+++ b/src/grpck.c
@@ -45,6 +45,7 @@
 #include "defines.h"
 #include "groupio.h"
 #include "nscd.h"
+#include "sssd.h"
 #include "prototypes.h"
 
 #ifdef SHADOWGRP
@@ -870,6 +871,7 @@ int main (int argc, char **argv)
 	close_files (changed);
 
 	nscd_flush_cache ("group");
+	sssd_flush_cache (SSSD_DB_GROUP);
 
 	/*
 	 * Tell the user what we did and exit.
diff --git a/src/grpconv.c b/src/grpconv.c
index f95f4960..5e5eaaca 100644
--- a/src/grpconv.c
+++ b/src/grpconv.c
@@ -48,6 +48,7 @@
 #include <unistd.h>
 #include <getopt.h>
 #include "nscd.h"
+#include "sssd.h"
 #include "prototypes.h"
 /*@-exitarg@*/
 #include "exitcodes.h"
@@ -273,6 +274,7 @@ int main (int argc, char **argv)
 	}
 
 	nscd_flush_cache ("group");
+	sssd_flush_cache (SSSD_DB_GROUP);
 
 	return 0;
 }
diff --git a/src/grpunconv.c b/src/grpunconv.c
index 253f06f5..e4105c26 100644
--- a/src/grpunconv.c
+++ b/src/grpunconv.c
@@ -48,6 +48,7 @@
 #include <grp.h>
 #include <getopt.h>
 #include "nscd.h"
+#include "sssd.h"
 #include "prototypes.h"
 /*@-exitarg@*/
 #include "exitcodes.h"
@@ -236,6 +237,7 @@ int main (int argc, char **argv)
 	}
 
 	nscd_flush_cache ("group");
+	sssd_flush_cache (SSSD_DB_GROUP);
 
 	return 0;
 }
diff --git a/src/newusers.c b/src/newusers.c
index 8e4bef97..7c3bb1c2 100644
--- a/src/newusers.c
+++ b/src/newusers.c
@@ -62,6 +62,7 @@
 #include "getdef.h"
 #include "groupio.h"
 #include "nscd.h"
+#include "sssd.h"
 #include "pwio.h"
 #include "sgroupio.h"
 #include "shadowio.h"
@@ -1233,6 +1234,7 @@ int main (int argc, char **argv)
 
 	nscd_flush_cache ("passwd");
 	nscd_flush_cache ("group");
+	sssd_flush_cache (SSSD_DB_PASSWD | SSSD_DB_GROUP);
 
 #ifdef USE_PAM
 	unsigned int i;
diff --git a/src/passwd.c b/src/passwd.c
index 3af3e651..5bea2765 100644
--- a/src/passwd.c
+++ b/src/passwd.c
@@ -51,6 +51,7 @@
 #include "defines.h"
 #include "getdef.h"
 #include "nscd.h"
+#include "sssd.h"
 #include "prototypes.h"
 #include "pwauth.h"
 #include "pwio.h"
@@ -1150,6 +1151,7 @@ int main (int argc, char **argv)
 
 	nscd_flush_cache ("passwd");
 	nscd_flush_cache ("group");
+	sssd_flush_cache (SSSD_DB_PASSWD | SSSD_DB_GROUP);
 
 	SYSLOG ((LOG_INFO, "password for '%s' changed by '%s'", name, myname));
 	closelog ();
diff --git a/src/pwck.c b/src/pwck.c
index 05df68ec..0ffb711e 100644
--- a/src/pwck.c
+++ b/src/pwck.c
@@ -48,6 +48,7 @@
 #include "shadowio.h"
 #include "getdef.h"
 #include "nscd.h"
+#include "sssd.h"
 #ifdef WITH_TCB
 #include "tcbfuncs.h"
 #endif				/* WITH_TCB */
@@ -877,6 +878,7 @@ int main (int argc, char **argv)
 	close_files (changed);
 
 	nscd_flush_cache ("passwd");
+	sssd_flush_cache (SSSD_DB_PASSWD);
 
 	/*
 	 * Tell the user what we did and exit.
diff --git a/src/pwconv.c b/src/pwconv.c
index d6ee31a8..9c69fa13 100644
--- a/src/pwconv.c
+++ b/src/pwconv.c
@@ -72,6 +72,7 @@
 #include "pwio.h"
 #include "shadowio.h"
 #include "nscd.h"
+#include "sssd.h"
 
 /*
  * exit status values
@@ -328,6 +329,7 @@ int main (int argc, char **argv)
 	}
 
 	nscd_flush_cache ("passwd");
+	sssd_flush_cache (SSSD_DB_PASSWD);
 
 	return E_SUCCESS;
 }
diff --git a/src/pwunconv.c b/src/pwunconv.c
index fabf0237..e11ea494 100644
--- a/src/pwunconv.c
+++ b/src/pwunconv.c
@@ -42,6 +42,7 @@
 #include <getopt.h>
 #include "defines.h"
 #include "nscd.h"
+#include "sssd.h"
 #include "prototypes.h"
 #include "pwio.h"
 #include "shadowio.h"
@@ -250,6 +251,7 @@ int main (int argc, char **argv)
 	}
 
 	nscd_flush_cache ("passwd");
+	sssd_flush_cache (SSSD_DB_PASSWD);
 
 	return 0;
 }
diff --git a/src/useradd.c b/src/useradd.c
index ca90f076..b0c2224d 100644
--- a/src/useradd.c
+++ b/src/useradd.c
@@ -60,6 +60,7 @@
 #include "getdef.h"
 #include "groupio.h"
 #include "nscd.h"
+#include "sssd.h"
 #include "prototypes.h"
 #include "pwauth.h"
 #include "pwio.h"
@@ -2425,6 +2426,7 @@ int main (int argc, char **argv)
 
 	nscd_flush_cache ("passwd");
 	nscd_flush_cache ("group");
+	sssd_flush_cache (SSSD_DB_PASSWD | SSSD_DB_GROUP);
 
 	/*
 	 * tallylog_reset needs to be able to lookup
diff --git a/src/userdel.c b/src/userdel.c
index c8de1d31..0715e4fe 100644
--- a/src/userdel.c
+++ b/src/userdel.c
@@ -53,6 +53,7 @@
 #include "getdef.h"
 #include "groupio.h"
 #include "nscd.h"
+#include "sssd.h"
 #include "prototypes.h"
 #include "pwauth.h"
 #include "pwio.h"
@@ -1328,6 +1329,7 @@ int main (int argc, char **argv)
 
 	nscd_flush_cache ("passwd");
 	nscd_flush_cache ("group");
+	sssd_flush_cache (SSSD_DB_PASSWD | SSSD_DB_GROUP);
 
 	return ((0 != errors) ? E_HOMEDIR : E_SUCCESS);
 }
diff --git a/src/usermod.c b/src/usermod.c
index 7355ad31..fd9a98a6 100644
--- a/src/usermod.c
+++ b/src/usermod.c
@@ -57,6 +57,7 @@
 #include "getdef.h"
 #include "groupio.h"
 #include "nscd.h"
+#include "sssd.h"
 #include "prototypes.h"
 #include "pwauth.h"
 #include "pwio.h"
@@ -2255,6 +2256,7 @@ int main (int argc, char **argv)
 
 	nscd_flush_cache ("passwd");
 	nscd_flush_cache ("group");
+	sssd_flush_cache (SSSD_DB_PASSWD | SSSD_DB_GROUP);
 
 #ifdef WITH_SELINUX
 	if (Zflg) {
diff --git a/src/vipw.c b/src/vipw.c
index 6d730f65..2cfac6b4 100644
--- a/src/vipw.c
+++ b/src/vipw.c
@@ -42,6 +42,7 @@
 #include "defines.h"
 #include "groupio.h"
 #include "nscd.h"
+#include "sssd.h"
 #include "prototypes.h"
 #include "pwio.h"
 #include "sgroupio.h"
@@ -556,6 +557,7 @@ int main (int argc, char **argv)
 
 	nscd_flush_cache ("passwd");
 	nscd_flush_cache ("group");
+	sssd_flush_cache (SSSD_DB_PASSWD | SSSD_DB_GROUP);
 
 	return E_SUCCESS;
 }