From 319b9ad4bccedb2a6b1a222cf446e873b2bc6de1 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Mon, 11 Jul 2011 14:50:24 -0400 Subject: 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. --- nss/nsswitch.c | 165 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 122 insertions(+), 43 deletions(-) (limited to 'nss/nsswitch.c') 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 , 1996. @@ -40,6 +41,7 @@ #include "nsswitch.h" #include "../nscd/nscd_proto.h" +#include /* 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. */ -- cgit v1.2.3