diff options
| author | DJ Delorie <dj@redhat.com> | 2020-11-09 22:06:57 -0500 |
|---|---|---|
| committer | DJ Delorie <dj@redhat.com> | 2020-12-04 17:15:53 -0500 |
| commit | f8847d83e17774ed5e9c0f75ef693680b91bcae4 (patch) | |
| tree | e67c662ee3cc09742242c19a253b5b62bbaa3ee7 | |
| parent | fa78feca47fdc226b46e7f6fea4c08c10fccd182 (diff) | |
| download | glibc-f8847d83e17774ed5e9c0f75ef693680b91bcae4.tar.xz glibc-f8847d83e17774ed5e9c0f75ef693680b91bcae4.zip | |
nsswitch: use new internal API (core)
Core changes to switch the NSS internals to use the new API.
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
| -rw-r--r-- | malloc/set-freeres.c | 4 | ||||
| -rw-r--r-- | nss/Makefile | 3 | ||||
| -rw-r--r-- | nss/nss_action.c | 2 | ||||
| -rw-r--r-- | nss/nss_action_parse.c | 22 | ||||
| -rw-r--r-- | nss/nss_database.c | 40 | ||||
| -rw-r--r-- | nss/nss_module.c | 64 | ||||
| -rw-r--r-- | nss/nsswitch.c | 809 | ||||
| -rw-r--r-- | nss/nsswitch.h | 69 |
8 files changed, 168 insertions, 845 deletions
diff --git a/malloc/set-freeres.c b/malloc/set-freeres.c index b328cca7c6..0769ad7a6f 100644 --- a/malloc/set-freeres.c +++ b/malloc/set-freeres.c @@ -20,7 +20,7 @@ #include <set-hooks.h> #include <libc-internal.h> -#include "../nss/nss_module.h" +#include "../nss/nsswitch.h" #include "../libio/libioP.h" DEFINE_HOOK (__libc_subfreeres, (void)); @@ -43,6 +43,8 @@ __libc_freeres (void) void *const *p; call_function_static_weak (__nss_module_freeres); + call_function_static_weak (__nss_action_freeres); + call_function_static_weak (__nss_database_freeres); _IO_cleanup (); diff --git a/nss/Makefile b/nss/Makefile index ccd1a6ae4f..83323cb934 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -66,7 +66,8 @@ tests-container = \ tst-nss-test3 \ tst-nss-files-hosts-long \ tst-nss-db-endpwent \ - tst-nss-db-endgrent + tst-nss-db-endgrent \ + tst-reload1 # Tests which need libdl ifeq (yes,$(build-shared)) diff --git a/nss/nss_action.c b/nss/nss_action.c index b9c3b93fea..5008323859 100644 --- a/nss/nss_action.c +++ b/nss/nss_action.c @@ -16,7 +16,7 @@ License along with the GNU C Library; if not, see <https://www.gnu.org/licenses/>. */ -#include <nss_action.h> +#include <nsswitch.h> #include <string.h> #include <libc-lock.h> diff --git a/nss/nss_action_parse.c b/nss/nss_action_parse.c index 1a7643a884..15c63a8ec3 100644 --- a/nss/nss_action_parse.c +++ b/nss/nss_action_parse.c @@ -16,8 +16,7 @@ License along with the GNU C Library; if not, see <https://www.gnu.org/licenses/>. */ -#include "nss_action.h" -#include "nss_module.h" +#include <nsswitch.h> #include <ctype.h> #include <string.h> @@ -169,18 +168,13 @@ nss_action_list action_list_init (&list); if (nss_action_parse (line, &list)) { - size_t size = action_list_size (&list); - nss_action_list result - = malloc (sizeof (*result) * (size + 1)); - if (result == NULL) - { - action_list_free (&list); - return NULL; - } - memcpy (result, action_list_begin (&list), sizeof (*result) * size); - /* Sentinel. */ - result[size].module = NULL; - return result; + size_t size; + struct nss_action null_service + = { .module = NULL, }; + + action_list_add (&list, null_service); + size = action_list_size (&list); + return __nss_action_allocate (action_list_begin (&list), size); } else if (action_list_has_failed (&list)) { diff --git a/nss/nss_database.c b/nss/nss_database.c index 329bfb1262..e8c307d1f3 100644 --- a/nss/nss_database.c +++ b/nss/nss_database.c @@ -226,6 +226,39 @@ process_line (struct nss_database_data *data, char *line) return true; } +int +__nss_configure_lookup (const char *dbname, const char *service_line) +{ + int db; + nss_action_list result; + struct nss_database_state *local; + + /* Convert named database to index. */ + db = name_to_database_index (dbname); + if (db < 0) + /* Not our database (e.g., sudoers). */ + return -1; + + /* Force any load/cache/read whatever to happen, so we can override + it. */ + __nss_database_get (db, &result); + + local = nss_database_state_get (); + + result = __nss_action_parse (service_line); + if (result == NULL) + return -1; + + atomic_store_release (&local->data.reload_disabled, 1); + local->data.services[db] = result; + +#ifdef USE_NSCD + __nss_database_custom[db] = true; +#endif + + return 0; +} + /* Iterate over the lines in FP, parse them, and store them in DATA. Return false on memory allocation failure, true on success. */ static bool @@ -326,8 +359,11 @@ nss_database_check_reload_and_get (struct nss_database_state *local, may have loaded the configuration first, so synchronize with the Release MO store there. */ if (atomic_load_acquire (&local->data.reload_disabled)) - /* No reload, so there is no error. */ - return true; + { + *result = local->data.services[database_index]; + /* No reload, so there is no error. */ + return true; + } struct file_change_detection initial; if (!__file_change_detection_for_path (&initial, _PATH_NSSWITCH_CONF)) diff --git a/nss/nss_module.c b/nss/nss_module.c index 8de8db09c3..fdb4e994df 100644 --- a/nss/nss_module.c +++ b/nss/nss_module.c @@ -16,7 +16,9 @@ License along with the GNU C Library; if not, see <https://www.gnu.org/licenses/>. */ -#include <nss_module.h> +#include <nsswitch.h> +#include <nscd/nscd.h> +#include <nscd/nscd_proto.h> #include <array_length.h> #include <assert.h> @@ -287,6 +289,66 @@ __nss_module_get_function (struct nss_module *module, const char *name) return fptr; } +#if defined SHARED && defined USE_NSCD +/* Load all libraries for the service. */ +static void +nss_load_all_libraries (const char *service, const char *def) +{ + nss_action_list ni = NULL; + + if (__nss_database_lookup2 (service, NULL, def, &ni) == 0) + while (ni->module != NULL) + { + __nss_module_load (ni->module); + ++ni; + } +} + +define_traced_file (pwd, _PATH_NSSWITCH_CONF); +define_traced_file (grp, _PATH_NSSWITCH_CONF); +define_traced_file (hst, _PATH_NSSWITCH_CONF); +define_traced_file (serv, _PATH_NSSWITCH_CONF); +define_traced_file (netgr, _PATH_NSSWITCH_CONF); + +/* Called by nscd and nscd alone. */ +void +__nss_disable_nscd (void (*cb) (size_t, struct traced_file *)) +{ + void (*cb1) (size_t, struct traced_file *); + cb1 = cb; +# 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", DEFAULT_CONFIG); + nss_load_all_libraries ("group", DEFAULT_CONFIG); + nss_load_all_libraries ("hosts", "dns [!UNAVAIL=return] files"); + nss_load_all_libraries ("services", NULL); + + /* Make sure NSCD purges its cache if nsswitch.conf changes. */ + init_traced_file (&pwd_traced_file.file, _PATH_NSSWITCH_CONF, 0); + cb1 (pwddb, &pwd_traced_file.file); + init_traced_file (&grp_traced_file.file, _PATH_NSSWITCH_CONF, 0); + cb1 (grpdb, &grp_traced_file.file); + init_traced_file (&hst_traced_file.file, _PATH_NSSWITCH_CONF, 0); + cb1 (hstdb, &hst_traced_file.file); + init_traced_file (&serv_traced_file.file, _PATH_NSSWITCH_CONF, 0); + cb1 (servdb, &serv_traced_file.file); + init_traced_file (&netgr_traced_file.file, _PATH_NSSWITCH_CONF, 0); + cb1 (netgrdb, &netgr_traced_file.file); + + /* 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; + __nss_not_use_nscd_netgroup = -1; +} +#endif + void __libc_freeres_fn_section __nss_module_freeres (void) { diff --git a/nss/nsswitch.c b/nss/nsswitch.c index 8d7b69d4bc..40109c744d 100644 --- a/nss/nsswitch.c +++ b/nss/nsswitch.c @@ -32,6 +32,7 @@ #include <netinet/ether.h> #include <pwd.h> #include <shadow.h> +#include <unistd.h> #if !defined DO_STATIC_NSS || defined SHARED # include <gnu/lib-names.h> @@ -42,36 +43,20 @@ #include <sysdep.h> #include <config.h> -/* Prototypes for the local functions. */ -static name_database *nss_parse_file (const char *fname); -static name_database_entry *nss_getline (char *line); -static service_user *nss_parse_service_list (const char *line); -#if !defined DO_STATIC_NSS || defined SHARED -static service_library *nss_new_service (name_database *database, - const char *name); -#endif - - /* Declare external database variables. */ #define DEFINE_DATABASE(name) \ - service_user *__nss_##name##_database attribute_hidden; \ + nss_action_list __nss_##name##_database attribute_hidden; \ weak_extern (__nss_##name##_database) #include "databases.def" #undef DEFINE_DATABASE -/* Structure to map database name to variable. */ -static const struct -{ - const char name[10]; - service_user **dbp; -} databases[] = -{ -#define DEFINE_DATABASE(name) \ - { #name, &__nss_##name##_database }, -#include "databases.def" + #undef DEFINE_DATABASE +#define DEFINE_DATABASE(name) #name, +static const char * database_names[] = { +#include "databases.def" + NULL }; -#define ndatabases (sizeof (databases) / sizeof (databases[0])) #ifdef USE_NSCD /* Flags whether custom rules for database is set. */ @@ -79,103 +64,33 @@ bool __nss_database_custom[NSS_DBSIDX_max]; #endif -__libc_lock_define_initialized (static, lock) - -#if !defined DO_STATIC_NSS || defined SHARED -/* String with revision number of the shared object files. */ -static const char *const __nss_shlib_revision = LIBNSS_FILES_SO + 15; -#endif - -/* The root of the whole data base. */ -static name_database *service_table; - -/* List of default service lists that were generated by glibc because - /etc/nsswitch.conf did not provide a value. - The list is only maintained so we can free such service lists in - __libc_freeres. */ -static name_database_entry *defconfig_entries; - - -#if defined USE_NSCD && (!defined DO_STATIC_NSS || defined SHARED) -/* 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 *); -#endif - +/*__libc_lock_define_initialized (static, lock)*/ /* -1 == database not found 0 == database entry pointer stored */ int __nss_database_lookup2 (const char *database, const char *alternate_name, - const char *defconfig, service_user **ni) + const char *defconfig, nss_action_list *ni) { - /* Prevent multiple threads to change the service table. */ - __libc_lock_lock (lock); + int database_id; - /* Reconsider database variable in case some other thread called - `__nss_configure_lookup' while we waited for the lock. */ - if (*ni != NULL) - { - __libc_lock_unlock (lock); - return 0; - } + for (database_id = 0; database_names[database_id]; database_id++) + if (strcmp (database_names[database_id], database) == 0) + break; - /* Are we initialized yet? */ - if (service_table == NULL) - /* Read config file. */ - service_table = nss_parse_file (_PATH_NSSWITCH_CONF); + if (database_names[database_id] == NULL) + return -1; - /* Test whether configuration data is available. */ - if (service_table != NULL) + if (__nss_database_get (database_id, ni)) { - /* Return first `service_user' entry for DATABASE. */ - name_database_entry *entry; - - /* XXX Could use some faster mechanism here. But each database is - only requested once and so this might not be critical. */ - for (entry = service_table->entry; entry != NULL; entry = entry->next) - if (strcmp (database, entry->name) == 0) - *ni = entry->service; - - if (*ni == NULL && alternate_name != NULL) - /* We haven't found an entry so far. Try to find it with the - alternative name. */ - for (entry = service_table->entry; entry != NULL; entry = entry->next) - if (strcmp (alternate_name, entry->name) == 0) - *ni = entry->service; + /* Success. */ + return 0; } - - /* No configuration data is available, either because nsswitch.conf - 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. */ - if (*ni == NULL) + else { - *ni = nss_parse_service_list (defconfig ?: "files"); - if (*ni != NULL) - { - /* Record the memory we've just allocated in defconfig_entries list, - so we can free it later. */ - name_database_entry *entry; - - /* Allocate ENTRY plus size of name (1 here). */ - entry = (name_database_entry *) malloc (sizeof (*entry) + 1); - - if (entry != NULL) - { - entry->next = defconfig_entries; - entry->service = *ni; - entry->name[0] = '\0'; - defconfig_entries = entry; - } - } + /* Failure. */ + return -1; } - - __libc_lock_unlock (lock); - - return *ni != NULL ? 0 : -1; } libc_hidden_def (__nss_database_lookup2) @@ -184,7 +99,7 @@ libc_hidden_def (__nss_database_lookup2) 0 == function found 1 == finished */ int -__nss_lookup (service_user **ni, const char *fct_name, const char *fct2_name, +__nss_lookup (nss_action_list *ni, const char *fct_name, const char *fct2_name, void **fctp) { *fctp = __nss_lookup_function (*ni, fct_name); @@ -193,16 +108,16 @@ __nss_lookup (service_user **ni, const char *fct_name, const char *fct2_name, while (*fctp == NULL && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE - && (*ni)->next != NULL) + && (*ni)[1].module != NULL) { - *ni = (*ni)->next; + ++(*ni); *fctp = __nss_lookup_function (*ni, fct_name); if (*fctp == NULL && fct2_name != NULL) *fctp = __nss_lookup_function (*ni, fct2_name); } - return *fctp != NULL ? 0 : (*ni)->next == NULL ? 1 : -1; + return *fctp != NULL ? 0 : (*ni)[1].module == NULL ? 1 : -1; } libc_hidden_def (__nss_lookup) @@ -211,7 +126,7 @@ libc_hidden_def (__nss_lookup) 0 == adjusted for next function 1 == finished */ int -__nss_next2 (service_user **ni, const char *fct_name, const char *fct2_name, +__nss_next2 (nss_action_list *ni, const char *fct_name, const char *fct2_name, void **fctp, int status, int all_values) { if (all_values) @@ -233,12 +148,12 @@ __nss_next2 (service_user **ni, const char *fct_name, const char *fct2_name, return 1; } - if ((*ni)->next == NULL) + if ((*ni)[1].module == NULL) return -1; do { - *ni = (*ni)->next; + ++(*ni); *fctp = __nss_lookup_function (*ni, fct_name); if (*fctp == NULL && fct2_name != NULL) @@ -246,675 +161,17 @@ __nss_next2 (service_user **ni, const char *fct_name, const char *fct2_name, } while (*fctp == NULL && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE - && (*ni)->next != NULL); + && (*ni)[1].module != NULL); return *fctp != NULL ? 0 : -1; } libc_hidden_def (__nss_next2) -int -__nss_configure_lookup (const char *dbname, const char *service_line) -{ - service_user *new_db; - size_t cnt; - - for (cnt = 0; cnt < ndatabases; ++cnt) - { - int cmp = strcmp (dbname, databases[cnt].name); - if (cmp == 0) - break; - if (cmp < 0) - { - __set_errno (EINVAL); - return -1; - } - } - - if (cnt == ndatabases) - { - __set_errno (EINVAL); - return -1; - } - - /* Test whether it is really used. */ - if (databases[cnt].dbp == NULL) - /* Nothing to do, but we could do. */ - return 0; - - /* Try to generate new data. */ - new_db = nss_parse_service_list (service_line); - if (new_db == NULL) - { - /* Illegal service specification. */ - __set_errno (EINVAL); - return -1; - } - - /* Prevent multiple threads to change the service table. */ - __libc_lock_lock (lock); - - /* Install new rules. */ - *databases[cnt].dbp = new_db; -#ifdef USE_NSCD - __nss_database_custom[cnt] = true; -#endif - - __libc_lock_unlock (lock); - - return 0; -} - - -/* Comparison function for searching NI->known tree. */ -static int -known_compare (const void *p1, const void *p2) -{ - return p1 == p2 ? 0 : strcmp (*(const char *const *) p1, - *(const char *const *) 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->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->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); - } -# ifdef USE_NSCD - else if (is_nscd) - { - /* Call the init function when nscd is used. */ - size_t initlen = (5 + strlen (ni->name) - + strlen ("_init") + 1); - char init_name[initlen]; - - /* Construct the init function name. */ - __stpcpy (__stpcpy (__stpcpy (init_name, - "_nss_"), - ni->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); - } - } -# endif - } - - return 0; -} -#endif - - void * -__nss_lookup_function (service_user *ni, const char *fct_name) -{ - void **found, *result; - - /* We now modify global data. Protect it. */ - __libc_lock_lock (lock); - - /* Search the tree of functions previously requested. Data in the - tree are `known_function' structures, whose first member is a - `const char *', the lookup key. The search returns a pointer to - the tree node structure; the first member of the is a pointer to - our structure (i.e. what will be a `known_function'); since the - first member of that is the lookup key string, &FCT_NAME is close - enough to a pointer to our structure to use as a lookup key that - will be passed to `known_compare' (above). */ - - found = __tsearch (&fct_name, &ni->known, &known_compare); - if (found == NULL) - /* This means out-of-memory. */ - result = NULL; - else if (*found != &fct_name) - { - /* The search found an existing structure in the tree. */ - result = ((known_function *) *found)->fct_ptr; -#ifdef PTR_DEMANGLE - PTR_DEMANGLE (result); -#endif - } - else - { - /* This name was not known before. Now we have a node in the tree - (in the proper sorted position for FCT_NAME) that points to - &FCT_NAME instead of any real `known_function' structure. - Allocate a new structure and fill it in. */ - - known_function *known = malloc (sizeof *known); - if (! known) - { -#if !defined DO_STATIC_NSS || defined SHARED - remove_from_tree: -#endif - /* Oops. We can't instantiate this node properly. - Remove it from the tree. */ - __tdelete (&fct_name, &ni->known, &known_compare); - free (known); - result = NULL; - } - else - { - /* Point the tree node at this new structure. */ - *found = known; - known->fct_name = fct_name; - -#if !defined DO_STATIC_NSS || defined SHARED - /* Load the appropriate library. */ - if (nss_load_library (ni) != 0) - /* This only happens when out of memory. */ - goto remove_from_tree; - - if (ni->library->lib_handle == (void *) -1l) - /* Library not found => function not found. */ - result = NULL; - else - |
