summaryrefslogtreecommitdiff
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)
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 *,