about summary refs log tree commit diff
path: root/nss
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@gmail.com>2011-07-11 14:50:24 -0400
committerUlrich Drepper <drepper@gmail.com>2011-07-11 14:50:24 -0400
commit319b9ad4bccedb2a6b1a222cf446e873b2bc6de1 (patch)
tree7951727c0dbd4394af52715e226745986e8beeb4 /nss
parent23bee3e8677c9357662ce789ed77fe25f3991c66 (diff)
downloadglibc-319b9ad4bccedb2a6b1a222cf446e873b2bc6de1.tar.gz
glibc-319b9ad4bccedb2a6b1a222cf446e873b2bc6de1.tar.xz
glibc-319b9ad4bccedb2a6b1a222cf446e873b2bc6de1.zip
Generalize framework to register monitoring of files in nscd
nscd can clear caches when certain files change.  The list of files
was hardcoded so far and worked for nss_files and nss_dns and those
modules which need no monitoring.  nss_db, for instance, has its
own set of files to monitor.  Now the NSS modules themselves can
request that certain files are monitored.
Diffstat (limited to 'nss')
-rw-r--r--nss/Makefile4
-rw-r--r--nss/Versions4
-rw-r--r--nss/nss_db/db-init.c54
-rw-r--r--nss/nss_files/files-init.c72
-rw-r--r--nss/nsswitch.c165
-rw-r--r--nss/nsswitch.h8
6 files changed, 259 insertions, 48 deletions
diff --git a/nss/Makefile b/nss/Makefile
index 60c65492ff..fb6428345b 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -66,14 +66,14 @@ vpath %.c $(subdir-dirs) ../locale/programs ../intl
 
 
 libnss_files-routines	:= $(addprefix files-,$(databases)) \
-			   files-initgroups files-have_o_cloexec
+			   files-initgroups files-have_o_cloexec files-init
 distribute		+= files-XXX.c files-parse.c
 
 libnss_db-dbs		:= $(addprefix db-,\
 				       $(filter-out hosts network key alias,\
 						    $(databases))) \
 			   db-initgroups
-libnss_db-routines	:= $(libnss_db-dbs) db-open hash-string
+libnss_db-routines	:= $(libnss_db-dbs) db-open db-init hash-string
 generated		+= $(filter-out db-alias.c db-netgrp.c, \
 					$(addsuffix .c,$(libnss_db-dbs)))
 distribute		+= $(addprefix nss_db/, db-XXX.c nss_db.h)
diff --git a/nss/Versions b/nss/Versions
index 913751217f..666915d6bf 100644
--- a/nss/Versions
+++ b/nss/Versions
@@ -97,6 +97,8 @@ libnss_files {
     _nss_files_getsecretkey;
 
     _nss_files_initgroups_dyn;
+
+    _nss_files_init;
   }
 }
 
@@ -153,5 +155,7 @@ libnss_db {
     _nss_db_getspnam_r;
 
     _nss_db_initgroups_dyn;
+
+    _nss_db_init;
   }
 }
diff --git a/nss/nss_db/db-init.c b/nss/nss_db/db-init.c
new file mode 100644
index 0000000000..8228d61f57
--- /dev/null
+++ b/nss/nss_db/db-init.c
@@ -0,0 +1,54 @@
+/* Initialization in nss_db module.
+   Copyright (C) 2011 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <paths.h>
+#include <nscd/nscd.h>
+
+
+static union
+{
+  struct traced_file file;
+  char buf[sizeof (struct traced_file) + sizeof (_PATH_VARDB "passwd.db")];
+} pwd_traced_file;
+
+static union
+{
+  struct traced_file file;
+  char buf[sizeof (struct traced_file) + sizeof (_PATH_VARDB "group.db")];
+} grp_traced_file;
+
+static union
+{
+  struct traced_file file;
+  char buf[sizeof (struct traced_file) + sizeof (_PATH_VARDB "services.db")];
+} serv_traced_file;
+
+
+void
+_nss_db_init (void (*cb) (size_t, struct traced_file *))
+{
+  strcpy (pwd_traced_file.file.fname,_PATH_VARDB  "passwd.db");
+  cb (pwddb, &pwd_traced_file.file);
+
+  strcpy (grp_traced_file.file.fname, _PATH_VARDB "group.db");
+  cb (grpdb, &grp_traced_file.file);
+
+  strcpy (serv_traced_file.file.fname, _PATH_VARDB "services.db");
+  cb (servdb, &serv_traced_file.file);
+}
diff --git a/nss/nss_files/files-init.c b/nss/nss_files/files-init.c
new file mode 100644
index 0000000000..cc6822d305
--- /dev/null
+++ b/nss/nss_files/files-init.c
@@ -0,0 +1,72 @@
+/* Initialization in nss_files module.
+   Copyright (C) 2011 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <nscd/nscd.h>
+
+
+static union
+{
+  struct traced_file file;
+  char buf[sizeof (struct traced_file) + sizeof ("/etc/passwd")];
+} pwd_traced_file;
+
+static union
+{
+  struct traced_file file;
+  char buf[sizeof (struct traced_file) + sizeof ("/etc/group")];
+} grp_traced_file;
+
+static union
+{
+  struct traced_file file;
+  char buf[sizeof (struct traced_file) + sizeof ("/etc/hosts")];
+} hst_traced_file;
+
+static union
+{
+  struct traced_file file;
+  char buf[sizeof (struct traced_file) + sizeof ("/etc/resolv.conf")];
+} resolv_traced_file;
+
+static union
+{
+  struct traced_file file;
+  char buf[sizeof (struct traced_file) + sizeof ("/etc/services")];
+} serv_traced_file;
+
+
+void
+_nss_files_init (void (*cb) (size_t, struct traced_file *))
+{
+  strcpy (pwd_traced_file.file.fname, "/etc/passwd");
+  cb (pwddb, &pwd_traced_file.file);
+
+  strcpy (grp_traced_file.file.fname, "/etc/group");
+  cb (grpdb, &grp_traced_file.file);
+
+  strcpy (hst_traced_file.file.fname, "/etc/hosts");
+  cb (hstdb, &hst_traced_file.file);
+
+  resolv_traced_file.file.call_res_init = 1;
+  strcpy (resolv_traced_file.file.fname, "/etc/resolv.conf");
+  cb (hstdb, &resolv_traced_file.file);
+
+  strcpy (serv_traced_file.file.fname, "/etc/services");
+  cb (servdb, &serv_traced_file.file);
+}
diff --git a/nss/nsswitch.c b/nss/nsswitch.c
index 92e6f5f91f..6c15c3a83f 100644
--- a/nss/nsswitch.c
+++ b/nss/nsswitch.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1996-1999,2001-2007,2009,2010 Free Software Foundation, Inc.
+/* Copyright (C) 1996-1999,2001-2007,2009,2010,2011
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
 
@@ -40,6 +41,7 @@
 
 #include "nsswitch.h"
 #include "../nscd/nscd_proto.h"
+#include <sysdep.h>
 
 /* Prototypes for the local functions.  */
 static name_database *nss_parse_file (const char *fname) internal_function;
@@ -86,6 +88,12 @@ static const char *const __nss_shlib_revision = LIBNSS_FILES_SO + 15;
 static name_database *service_table;
 
 
+/* Nonzero if this is the nscd process.  */
+static bool is_nscd;
+/* The callback passed to the init functions when nscd is used.  */
+static void (*nscd_init_cb) (size_t, struct traced_file *);
+
+
 /* -1 == database not found
     0 == database entry pointer stored */
 int
@@ -129,7 +137,7 @@ __nss_database_lookup (const char *database, const char *alternate_name,
     }
 
   /* No configuration data is available, either because nsswitch.conf
-     doesn't exist or because it doesn't has a line for this database.
+     doesn't exist or because it doesn't have a line for this database.
 
      DEFCONFIG specifies the default service list for this database,
      or null to use the most common default.  */
@@ -285,6 +293,79 @@ known_compare (const void *p1, const void *p2)
 }
 
 
+#if !defined DO_STATIC_NSS || defined SHARED
+/* Load library.  */
+static int
+nss_load_library (service_user *ni)
+{
+  if (ni->library == NULL)
+    {
+      /* This service has not yet been used.  Fetch the service
+	 library for it, creating a new one if need be.  If there
+	 is no service table from the file, this static variable
+	 holds the head of the service_library list made from the
+	 default configuration.  */
+      static name_database default_table;
+      ni->library = nss_new_service (service_table ?: &default_table,
+				     ni->name);
+      if (ni->library == NULL)
+	return -1;
+    }
+
+  if (ni->library->lib_handle == NULL)
+    {
+      /* Load the shared library.  */
+      size_t shlen = (7 + strlen (ni->library->name) + 3
+		      + strlen (__nss_shlib_revision) + 1);
+      int saved_errno = errno;
+      char shlib_name[shlen];
+
+      /* Construct shared object name.  */
+      __stpcpy (__stpcpy (__stpcpy (__stpcpy (shlib_name,
+					      "libnss_"),
+				    ni->library->name),
+			  ".so"),
+		__nss_shlib_revision);
+
+      ni->library->lib_handle = __libc_dlopen (shlib_name);
+      if (ni->library->lib_handle == NULL)
+	{
+	  /* Failed to load the library.  */
+	  ni->library->lib_handle = (void *) -1l;
+	  __set_errno (saved_errno);
+	}
+      else if (is_nscd)
+	{
+	  /* Call the init function when nscd is used.  */
+	  size_t initlen = (5 + strlen (ni->library->name)
+			    + strlen ("_init") + 1);
+	  char init_name[initlen];
+
+	  /* Construct the init function name.  */
+	  __stpcpy (__stpcpy (__stpcpy (init_name,
+					"_nss_"),
+			      ni->library->name),
+		    "_init");
+
+	  /* Find the optional init function.  */
+	  void (*ifct) (void (*) (size_t, struct traced_file *))
+	    = __libc_dlsym (ni->library->lib_handle, init_name);
+	  if (ifct != NULL)
+	    {
+	      void (*cb) (size_t, struct traced_file *) = nscd_init_cb;
+# ifdef PTR_DEMANGLE
+	      PTR_DEMANGLE (cb);
+# endif
+	      ifct (cb);
+	    }
+	}
+    }
+
+  return 0;
+}
+#endif
+
+
 void *
 __nss_lookup_function (service_user *ni, const char *fct_name)
 {
@@ -331,47 +412,13 @@ __nss_lookup_function (service_user *ni, const char *fct_name)
 	  *found = known;
 	  known->fct_name = fct_name;
 
-	  if (ni->library == NULL)
-	    {
-	      /* This service has not yet been used.  Fetch the service
-		 library for it, creating a new one if need be.  If there
-		 is no service table from the file, this static variable
-		 holds the head of the service_library list made from the
-		 default configuration.  */
-	      static name_database default_table;
-	      ni->library = nss_new_service (service_table ?: &default_table,
-					     ni->name);
-	      if (ni->library == NULL)
-		{
-		  /* This only happens when out of memory.  */
-		  free (known);
-		  goto remove_from_tree;
-		}
-	    }
-
 #if !defined DO_STATIC_NSS || defined SHARED
-	  if (ni->library->lib_handle == NULL)
+	  /* Load the appropriate library.  */
+	  if (nss_load_library (ni) != 0)
 	    {
-	      /* Load the shared library.  */
-	      size_t shlen = (7 + strlen (ni->library->name) + 3
-			      + strlen (__nss_shlib_revision) + 1);
-	      int saved_errno = errno;
-	      char shlib_name[shlen];
-
-	      /* Construct shared object name.  */
-	      __stpcpy (__stpcpy (__stpcpy (__stpcpy (shlib_name,
-						      "libnss_"),
-					    ni->library->name),
-				  ".so"),
-			__nss_shlib_revision);
-
-	      ni->library->lib_handle = __libc_dlopen (shlib_name);
-	      if (ni->library->lib_handle == NULL)
-		{
-		  /* Failed to load the library.  */
-		  ni->library->lib_handle = (void *) -1l;
-		  __set_errno (saved_errno);
-		}
+	      /* This only happens when out of memory.  */
+	      free (known);
+	      goto remove_from_tree;
 	    }
 
 	  if (ni->library->lib_handle == (void *) -1l)
@@ -463,7 +510,10 @@ nss_parse_file (const char *fname)
 
   result = (name_database *) malloc (sizeof (name_database));
   if (result == NULL)
-    return NULL;
+    {
+      fclose (fp);
+      return NULL;
+    }
 
   result->entry = NULL;
   result->library = NULL;
@@ -724,16 +774,45 @@ nss_new_service (name_database *database, const char *name)
 }
 
 
+#ifdef SHARED
+/* Load all libraries for the service.  */
+static void
+nss_load_all_libraries (const char *service, const char *def)
+{
+  service_user *ni = NULL;
+
+  if (__nss_database_lookup (service, NULL, def, &ni) == 0)
+    while (ni != NULL)
+      {
+	nss_load_library (ni);
+	ni = ni->next;
+      }
+}
+
+
 /* Called by nscd and nscd alone.  */
 void
-__nss_disable_nscd (void)
+__nss_disable_nscd (void (*cb) (size_t, struct traced_file *))
 {
+# ifdef PTR_MANGLE
+  PTR_MANGLE (cb);
+# endif
+  nscd_init_cb = cb;
+  is_nscd = true;
+
+  /* Find all the relevant modules so that the init functions are called.  */
+  nss_load_all_libraries ("passwd", "compat [NOTFOUND=return] files");
+  nss_load_all_libraries ("group", "compat [NOTFOUND=return] files");
+  nss_load_all_libraries ("hosts", "dns [!UNAVAIL=return] files");
+  nss_load_all_libraries ("services", NULL);
+
   /* Disable all uses of NSCD.  */
   __nss_not_use_nscd_passwd = -1;
   __nss_not_use_nscd_group = -1;
   __nss_not_use_nscd_hosts = -1;
   __nss_not_use_nscd_services = -1;
 }
+#endif
 
 
 /* Free all resources if necessary.  */
diff --git a/nss/nsswitch.h b/nss/nsswitch.h
index ae5657e889..3e37bc8bd8 100644
--- a/nss/nsswitch.h
+++ b/nss/nsswitch.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-1999,2001,2002,2003,2004,2007,2010
+/* Copyright (C) 1996-1999,2001,2002,2003,2004,2007,2010,2011
    Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
@@ -153,8 +153,10 @@ extern void *__nss_lookup_function (service_user *ni, const char *fct_name);
 libc_hidden_proto (__nss_lookup_function)
 
 
-/* Called by NSCD to disable recursive calls.  */
-extern void __nss_disable_nscd (void);
+/* Called by NSCD to disable recursive calls and enable special handling
+   when used in nscd.  */
+struct traced_file;
+extern void __nss_disable_nscd (void (*) (size_t, struct traced_file *));
 
 
 typedef int (*db_lookup_function) (service_user **, const char *, const char *,