From patchwork Thu Jun 25 04:04:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: DJ Delorie X-Patchwork-Id: 39795 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id CAFB03892457; Thu, 25 Jun 2020 04:04:53 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CAFB03892457 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1593057893; bh=9z4dy7G5z2ZOlrNJ43tzOIrlqKcIn31FzwkzXl0tKMA=; h=Date:To:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=QuYtZuOWbiDj9HNViIn9ddpg/NA+oU8MGeHB98HS0HwqtAoGB7OaB+QhkrHTKBUmJ +iGTeH+Uoo/R5OqGXwW1E6gL//ttwpTCOFMgUBTbMDRQUYqtY596w9a00gEfOxDHNd cBljw3XsYwSxYmMR6uofRRUyFjK9KKyjwcw2THlE= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [205.139.110.120]) by sourceware.org (Postfix) with ESMTP id CA3BE3887019 for ; Thu, 25 Jun 2020 04:04:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org CA3BE3887019 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-140-GJxp8ApPNqW5KpUy1dQ7Gw-1; Thu, 25 Jun 2020 00:04:46 -0400 X-MC-Unique: GJxp8ApPNqW5KpUy1dQ7Gw-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id B72BB805EF2 for ; Thu, 25 Jun 2020 04:04:45 +0000 (UTC) Received: from greed.delorie.com (ovpn-112-186.phx2.redhat.com [10.3.112.186]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 7A8CE61986 for ; Thu, 25 Jun 2020 04:04:45 +0000 (UTC) Received: from greed.delorie.com.redhat.com (localhost [127.0.0.1]) by greed.delorie.com (8.14.7/8.14.7) with ESMTP id 05P44iZL023194 for ; Thu, 25 Jun 2020 00:04:44 -0400 Date: Thu, 25 Jun 2020 00:04:44 -0400 Message-Id: To: libc-alpha@sourceware.org Subject: [PATCH 1/4] nss: Introduce X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-13.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP, T_FILL_THIS_FORM_SHORT autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: DJ Delorie via Libc-alpha From: DJ Delorie Reply-To: DJ Delorie Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" This provides the struct nss_module type, which combines the old struct service_library type with the known_function tree, by statically allocating space for all function pointers. struct nss_module is fairly large (536 bytes), but it will be shared across NSS databases. The old known_function handling had non-some per-function overhead (at least 32 bytes per looked-up function, but more for long function anmes), so overall, this is not too bad. Resolving all functions at load time simplifies locking, and the repeated lookups should be fast because the caches are hot at this point. --- malloc/set-freeres.c | 3 + nss/Makefile | 2 +- nss/nss_module.c | 300 +++++++++++++++++++++++++++++++++++++++++++ nss/nss_module.h | 152 ++++++++++++++++++++++ 4 files changed, 456 insertions(+), 1 deletion(-) create mode 100644 nss/nss_module.c create mode 100644 nss/nss_module.h diff --git a/malloc/set-freeres.c b/malloc/set-freeres.c index aa80eb64b8..b328cca7c6 100644 --- a/malloc/set-freeres.c +++ b/malloc/set-freeres.c @@ -20,6 +20,7 @@ #include #include +#include "../nss/nss_module.h" #include "../libio/libioP.h" DEFINE_HOOK (__libc_subfreeres, (void)); @@ -41,6 +42,8 @@ __libc_freeres (void) { void *const *p; + call_function_static_weak (__nss_module_freeres); + _IO_cleanup (); /* We run the resource freeing after IO cleanup. */ diff --git a/nss/Makefile b/nss/Makefile index 97bab5bb75..5d357eb51e 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -28,7 +28,7 @@ headers := nss.h routines = nsswitch getnssent getnssent_r digits_dots \ valid_field valid_list_field rewrite_field \ $(addsuffix -lookup,$(databases)) \ - compat-lookup nss_hash + compat-lookup nss_hash nss_module # These are the databases that go through nss dispatch. # Caution: if you add a database here, you must add its real name diff --git a/nss/nss_module.c b/nss/nss_module.c new file mode 100644 index 0000000000..29dc1139c6 --- /dev/null +++ b/nss/nss_module.c @@ -0,0 +1,300 @@ +/* Global list of NSS service modules. + Copyright (c) 2020 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, see + . */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Suffix after .so of NSS service modules. */ +static const char *const __nss_shlib_revision = LIBNSS_FILES_SO + 15; + +/* A single-linked list used to implement a mapping from names to NSS + modules. (Most systems only use five or so service modules, so a + list is sufficient here.) Elements of this list are never freed + during normal operation. */ +static struct nss_module *nss_module_list; + +/* Covers the list and also loading of individual NSS service + modules. */ +__libc_lock_define (static, nss_module_list_lock); + +struct nss_module * +__nss_module_allocate (const char *name, size_t name_length) +{ + __libc_lock_lock (nss_module_list_lock); + + struct nss_module *result = NULL; + for (struct nss_module *p = nss_module_list; p != NULL; p = p->next) + if (strncmp (p->name, name, name_length) == 0 + && p->name[name_length] == '\0') + { + /* Return the previously existing object. */ + result = p; + break; + } + + if (result == NULL) + { + /* Allocate a new list entry if the name was not found in the + list. */ + result = malloc (sizeof (*result) + name_length + 1); + if (result != NULL) + { + result->state = nss_module_uninitialized; + memcpy (result->name, name, name_length); + result->name[name_length] = '\0'; + result->handle = NULL; + result->next = nss_module_list; + nss_module_list = result; + } + } + + __libc_lock_unlock (nss_module_list_lock); + return result; +} + +/* Long enough to store the name of any function. */ +typedef char function_name[19]; + +/* This must be lexicographically sorted and match struct + nss_module_functions. */ +static const function_name nss_function_name_array[] = + { + "endaliasent", + "endetherent", + "endgrent", + "endhostent", + "endnetent", + "endnetgrent", + "endprotoent", + "endpwent", + "endrpcent", + "endservent", + "endsgent", + "endspent", + "getaliasbyname_r", + "getaliasent_r", + "getcanonname_r", + "getetherent_r", + "getgrent_r", + "getgrgid_r", + "getgrnam_r", + "gethostbyaddr2_r", + "gethostbyaddr_r", + "gethostbyname2_r", + "gethostbyname3_r", + "gethostbyname4_r", + "gethostbyname_r", + "gethostent_r", + "gethostton_r", + "getnetbyaddr_r", + "getnetbyname_r", + "getnetent_r", + "getnetgrent_r", + "getntohost_r", + "getprotobyname_r", + "getprotobynumber_r", + "getprotoent_r", + "getpublickey", + "getpwent_r", + "getpwnam_r", + "getpwuid_r", + "getrpcbyname_r", + "getrpcbynumber_r", + "getrpcent_r", + "getsecretkey", + "getservbyname_r", + "getservbyport_r", + "getservent_r", + "getsgent_r", + "getsgnam_r", + "getspent_r", + "getspnam_r", + "initgroups_dyn", + "netname2user", + "setaliasent", + "setetherent", + "setgrent", + "sethostent", + "setnetent", + "setnetgrent", + "setprotoent", + "setpwent", + "setrpcent", + "setservent", + "setsgent", + "setspent", + }; + +_Static_assert ((array_length (nss_function_name_array) * sizeof (void *)) + == sizeof (struct nss_module_functions), + "length of nss_module_name_array"); +_Static_assert (array_length (nss_function_name_array) + == array_length ((struct nss_module) { 0 }.functions.untyped), + "length of nss_module_name_array"); + +static bool +module_load (struct nss_module *module) +{ + void *handle; + { + char *shlib_name; + if (__asprintf (&shlib_name, "libnss_%s.so%s", + module->name, __nss_shlib_revision) < 0) + /* This is definitely a temporary failure. Do not update + module->state. This will trigger another attempt at the next + call. */ + return false; + + handle = __libc_dlopen (shlib_name); + free (shlib_name); + } + + if (handle == NULL) + { + /* dlopen failure. We do not know if this a temporary or + permanent error. See bug 22041. Update the state using the + double-checked locking idiom. */ + + __libc_lock_lock (nss_module_list_lock); + bool result = result; + switch ((enum nss_module_state) atomic_load_acquire (&module->state)) + { + case nss_module_uninitialized: + atomic_store_release (&module->state, nss_module_failed); + result = false; + break; + case nss_module_loaded: + result = true; + break; + case nss_module_failed: + result = false; + break; + } + __libc_lock_unlock (nss_module_list_lock); + return result; + } + + nss_module_functions_untyped pointers; + + for (size_t idx = 0; idx < array_length (nss_function_name_array); ++idx) + { + char *function_name; + if (__asprintf (&function_name, "_nss_%s_%s", + module->name, nss_function_name_array[idx]) < 0) + { + /* Definitely a temporary error. */ + __libc_dlclose (handle); + return false; + } + pointers[idx] = __libc_dlsym (handle, function_name); + free (function_name); +#ifdef PTR_MANGLE + PTR_MANGLE (pointers[idx]); +#endif + } + + /* Intall the function pointers, following the double-checked + locking idiom. Delay this after all processing, in case loading + the module triggers unwinding. */ + __libc_lock_lock (nss_module_list_lock); + switch ((enum nss_module_state) atomic_load_acquire (&module->state)) + { + case nss_module_uninitialized: + case nss_module_failed: + memcpy (module->functions.untyped, pointers, + sizeof (module->functions.untyped)); + module->handle = handle; + atomic_store_release (&module->state, nss_module_loaded); + break; + case nss_module_loaded: + /* This does not actually unload the module, only the reference + counter is decremented. */ + __libc_dlclose (handle); + break; + } + __libc_lock_unlock (nss_module_list_lock); + return true; +} + +/* Ensures that MODULE is in a loaded or failed state. */ +bool +__nss_module_load (struct nss_module *module) +{ + switch ((enum nss_module_state) atomic_load_acquire (&module->state)) + { + case nss_module_uninitialized: + return module_load (module); + case nss_module_loaded: + /* Loading has already succeeded. */ + return true; + case nss_module_failed: + /* Loading previously failed. */ + return false; + } + __builtin_unreachable (); +} + +static int +name_search (const void *left, const void *right) +{ + return strcmp (left, right); +} + +void * +__nss_module_get_function (struct nss_module *module, const char *name) +{ + if (!__nss_module_load (module)) + return NULL; + + function_name *name_entry = bsearch (name, nss_function_name_array, + array_length (nss_function_name_array), + sizeof (function_name), name_search); + assert (name_entry != NULL); + size_t idx = name_entry - nss_function_name_array; + void *fptr = module->functions.untyped[idx]; +#ifdef PTR_DEMANGLE + PTR_DEMANGLE (fptr); +#endif + return fptr; +} + +void __libc_freeres_fn_section +__nss_module_freeres (void) +{ + struct nss_module *current = nss_module_list; + while (current != NULL) + { + if (current->state == nss_module_loaded) + __libc_dlclose (current->handle); + + struct nss_module *next = current->next; + free (current); + current = next; + } + nss_module_list = NULL; +} diff --git a/nss/nss_module.h b/nss/nss_module.h new file mode 100644 index 0000000000..745f99a58e --- /dev/null +++ b/nss/nss_module.h @@ -0,0 +1,152 @@ +/* Global list of NSS service modules. + Copyright (c) 2020 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, see + . */ + +#ifndef _NSS_MODULE_H +#define _NSS_MODULE_H + +#include +#include + +/* Typed function pointers for all functions that can be defined by a + service module. */ +struct nss_module_functions +{ + nss_endaliasent *endaliasent; + nss_endetherent *endetherent; + nss_endgrent *endgrent; + nss_endhostent *endhostent; + nss_endnetent *endnetent; + nss_endnetgrent *endnetgrent; + nss_endprotoent *endprotoent; + nss_endpwent *endpwent; + nss_endrpcent *endrpcent; + nss_endservent *endservent; + nss_endsgent *endsgent; + nss_endspent *endspent; + nss_getaliasbyname_r *getaliasbyname_r; + nss_getaliasent_r *getaliasent_r; + nss_getcanonname_r *getcanonname_r; + nss_getetherent_r *getetherent_r; + nss_getgrent_r *getgrent_r; + nss_getgrgid_r *getgrgid_r; + nss_getgrnam_r *getgrnam_r; + nss_gethostbyaddr2_r *gethostbyaddr2_r; + nss_gethostbyaddr_r *gethostbyaddr_r; + nss_gethostbyname2_r *gethostbyname2_r; + nss_gethostbyname3_r *gethostbyname3_r; + nss_gethostbyname4_r *gethostbyname4_r; + nss_gethostbyname_r *gethostbyname_r; + nss_gethostent_r *gethostent_r; + nss_gethostton_r *gethostton_r; + nss_getnetbyaddr_r *getnetbyaddr_r; + nss_getnetbyname_r *getnetbyname_r; + nss_getnetent_r *getnetent_r; + nss_getnetgrent_r *getnetgrent_r; + nss_getntohost_r *getntohost_r; + nss_getprotobyname_r *getprotobyname_r; + nss_getprotobynumber_r *getprotobynumber_r; + nss_getprotoent_r *getprotoent_r; + nss_getpublickey *getpublickey; + nss_getpwent_r *getpwent_r; + nss_getpwnam_r *getpwnam_r; + nss_getpwuid_r *getpwuid_r; + nss_getrpcbyname_r *getrpcbyname_r; + nss_getrpcbynumber_r *getrpcbynumber_r; + nss_getrpcent_r *getrpcent_r; + nss_getsecretkey *getsecretkey; + nss_getservbyname_r *getservbyname_r; + nss_getservbyport_r *getservbyport_r; + nss_getservent_r *getservent_r; + nss_getsgent_r *getsgent_r; + nss_getsgnam_r *getsgnam_r; + nss_getspent_r *getspent_r; + nss_getspnam_r *getspnam_r; + nss_initgroups_dyn *initgroups_dyn; + nss_netname2user *netname2user; + nss_setaliasent *setaliasent; + nss_setetherent *setetherent; + nss_setgrent *setgrent; + nss_sethostent *sethostent; + nss_setnetent *setnetent; + nss_setnetgrent *setnetgrent; + nss_setprotoent *setprotoent; + nss_setpwent *setpwent; + nss_setrpcent *setrpcent; + nss_setservent *setservent; + nss_setsgent *setsgent; + nss_setspent *setspent; +}; + +/* Untyped version of struct nss_module_functions, for consistent + processing purposes. */ +typedef void *nss_module_functions_untyped[sizeof (struct nss_module_functions) + / sizeof (void *)]; + +/* Initialization state of a NSS module. */ +enum nss_module_state +{ + nss_module_uninitialized, + nss_module_loaded, + nss_module_failed, +}; + +/* A NSS service module (potentially unloaded). Client code should + use the functions below. */ +struct nss_module +{ + /* Actual type is enum nss_module_state. Use int due to atomic + access. Used in a double-checked locking idiom. */ + int state; + + /* The function pointers in the module. */ + union + { + struct nss_module_functions typed; + nss_module_functions_untyped untyped; + } functions; + + /* Only used for __libc_freeres unloading. */ + void *handle; + + /* The next module in the list. */ + struct nss_module *next; + + /* The name of the module (as it appears in /etc/nsswitch.conf). */ + char name[]; +}; + +/* Allocates the NSS module NAME (of NAME_LENGTH bytes) and places it + into the global list. If it already exists in the list, return the + pre-existing module. This does not actually load the module. + Returns NULL on memory allocation failure. */ +struct nss_module *__nss_module_allocate (const char *name, + size_t name_length) attribute_hidden; + +/* Ensures that MODULE is in a loaded or failed state. */ +bool __nss_module_load (struct nss_module *module) attribute_hidden; + +/* Ensures that MODULE is loaded and returns a pointer to the function + NAME defined in it. Returns NULL if MODULE could not be loaded, or + if the function NAME is not defined in the module. */ +void *__nss_module_get_function (struct nss_module *module, const char *name) + attribute_hidden; + +/* Called from __libc_freeres. */ +void __nss_module_freeres (void) attribute_hidden; + +#endif /* NSS_MODULE_H */ From patchwork Thu Jun 25 04:05:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: DJ Delorie X-Patchwork-Id: 39796 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E5FAB3892463; Thu, 25 Jun 2020 04:05:12 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E5FAB3892463 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1593057913; bh=jhCXJ/qqim6zFtBGL3ri2UD12G8xRRHRFNucVcnZueA=; h=Date:To:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=fvbIfkUeC6c04DvdVBmIizce4yHsNvbCGZWI49Rzw4rKBcU07BtHUue535iOZpCJJ 5f9LEUzrVhIG3ZKzfBgkf/2JW1x78+P4mKt5J4edJhL9xrWYUoI5cv57CZzSMP9S7q ire2lj3R240Sw1mvMFh2grdVCNwI6m7ZUj0a3n50= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-1.mimecast.com (us-smtp-1.mimecast.com [207.211.31.81]) by sourceware.org (Postfix) with ESMTP id B239C3887019 for ; Thu, 25 Jun 2020 04:05:09 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org B239C3887019 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-507-YW_D3RSkPoWVdfxn528wmA-1; Thu, 25 Jun 2020 00:05:07 -0400 X-MC-Unique: YW_D3RSkPoWVdfxn528wmA-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 5CE5318585A2 for ; Thu, 25 Jun 2020 04:05:06 +0000 (UTC) Received: from greed.delorie.com (ovpn-112-186.phx2.redhat.com [10.3.112.186]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 207685DA27 for ; Thu, 25 Jun 2020 04:05:06 +0000 (UTC) Received: from greed.delorie.com.redhat.com (localhost [127.0.0.1]) by greed.delorie.com (8.14.7/8.14.7) with ESMTP id 05P455jR023202 for ; Thu, 25 Jun 2020 00:05:05 -0400 Date: Thu, 25 Jun 2020 00:05:05 -0400 Message-Id: To: libc-alpha@sourceware.org Subject: [PATCH 2/4] : New abstraction for combining NSS modules and NSS actions X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-13.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: DJ Delorie via Libc-alpha From: DJ Delorie Reply-To: DJ Delorie Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" --- nss/Makefile | 3 +- nss/nss_action.c | 114 ++++++++++++++++++++++++ nss/nss_action.h | 92 +++++++++++++++++++ nss/nss_action_parse.c | 197 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 405 insertions(+), 1 deletion(-) create mode 100644 nss/nss_action.c create mode 100644 nss/nss_action.h create mode 100644 nss/nss_action_parse.c diff --git a/nss/Makefile b/nss/Makefile index 5d357eb51e..464655d045 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -28,7 +28,8 @@ headers := nss.h routines = nsswitch getnssent getnssent_r digits_dots \ valid_field valid_list_field rewrite_field \ $(addsuffix -lookup,$(databases)) \ - compat-lookup nss_hash nss_module + compat-lookup nss_hash nss_module nss_action \ + nss_action_parse # These are the databases that go through nss dispatch. # Caution: if you add a database here, you must add its real name diff --git a/nss/nss_action.c b/nss/nss_action.c new file mode 100644 index 0000000000..24f1c5e4f9 --- /dev/null +++ b/nss/nss_action.c @@ -0,0 +1,114 @@ +/* NSS actions, elements in a nsswitch.conf configuration line. + Copyright (c) 2020 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, see + . */ + +#include + +#include +#include + +/* Maintain a global list of NSS action lists. Since most databases + use the same list of actions, this list is usually short. + Deduplication in __nss_action_allocate ensures that the list does + not grow without bounds. */ + +struct nss_action_list_wrapper +{ + /* The next element of the list.x */ + struct nss_action_list_wrapper *next; + + /* Number of elements in the list (excluding the terminator). */ + size_t count; + + /* NULL-terminated list of actions. */ + struct nss_action actions[]; +}; + +/* Global list of allocated NSS action lists. */ +struct nss_action_list_wrapper *nss_actions; + +/* Covers the list. */ +__libc_lock_define (static, nss_actions_lock); + +/* Returns true if the actions are equal (same module, same actions + aray). */ +static bool +actions_equal (const struct nss_action *a, const struct nss_action *b) +{ + return a->module == b->module && a->action_bits == b->action_bits; +} + +/* Returns true if the COUNT actions at A and B are equal (according + to actions_equal above). */ +static bool +action_lists_equal (const struct nss_action *a, const struct nss_action *b, + size_t count) +{ + for (size_t i = 0; i < count; ++i) + if (!actions_equal (a + i, b + i)) + return false; + return true; +} + +/* Returns a pre-allocated action list for COUNT actions at ACTIONS, + or NULL if no such list exists. */ +static nss_action_list +find_allocated (struct nss_action *actions, size_t count) +{ + for (struct nss_action_list_wrapper *p = nss_actions; p != NULL; p = p->next) + if (p->count == count && action_lists_equal (p->actions, actions, count)) + return p->actions; + return NULL; +} + +nss_action_list +__nss_action_allocate (struct nss_action *actions, size_t count) +{ + nss_action_list result = NULL; + __libc_lock_lock (nss_actions_lock); + + result = find_allocated (actions, count); + if (result == NULL) + { + struct nss_action_list_wrapper *wrapper + = malloc (sizeof (*wrapper) + sizeof (*actions) * count); + if (wrapper != NULL) + { + wrapper->next = nss_actions; + wrapper->count = count; + memcpy (wrapper->actions, actions, sizeof (*actions) * count); + nss_actions = wrapper; + result = wrapper->actions; + } + } + + __libc_lock_unlock (nss_actions_lock); + return result; +} + +void __libc_freeres_fn_section +__nss_action_freeres (void) +{ + struct nss_action_list_wrapper *current = nss_actions; + while (current != NULL) + { + struct nss_action_list_wrapper *next = current->next; + free (current); + current = next; + } + nss_actions = NULL; +} diff --git a/nss/nss_action.h b/nss/nss_action.h new file mode 100644 index 0000000000..7c0d3ef505 --- /dev/null +++ b/nss/nss_action.h @@ -0,0 +1,92 @@ +/* NSS actions, elements in a nsswitch.conf configuration line. + Copyright (c) 2020 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, see + . */ + +#ifndef _NSS_ACTION_H +#define _NSS_ACTION_H + +#include + +#include "nsswitch.h" /* For lookup_actions. */ + +struct nss_module; + +/* A NSS action pairs a service module with the action for each result + state. */ +struct nss_action +{ + /* The service module that provides the functionality (potentially + not yet loaded). */ + struct nss_module *module; + + /* Action according to result. Two bits for each lookup_actions + value (from nsswitch.h), indexed by enum nss_status (from nss.h). */ + unsigned int action_bits; +}; + +/* Index in actions. */ +static inline int +nss_actions_bits_index (enum nss_status status) +{ + return 2 * (2 + status); +} + +/* Returns the lookup_action value for STATUS in ACTION. */ +static inline lookup_actions +nss_action_get (const struct nss_action *action, enum nss_status status) +{ + return (action->action_bits >> nss_actions_bits_index (status)) & 3; +} + +/* Sets the lookup_action value for STATUS in ACTION. */ +static inline void +nss_action_set (struct nss_action *action, + enum nss_status status, lookup_actions actions) +{ + int offset = nss_actions_bits_index (status); + unsigned int mask = 3 << offset; + action->action_bits = ((action->action_bits & ~mask) + | ((unsigned int) actions << offset)); +} + +static inline void +nss_action_set_all (struct nss_action *action, lookup_actions actions) +{ + unsigned int bits = actions; + /* Produces 0b00 .. 00 AA AA AA AA AA. */ + action->action_bits = bits * 0x155; +} + +/* A list of struct nss_action objects in array terminated by an + action with a NULL module. */ +typedef struct nss_action *nss_action_list; + +/* Returns a pointer to an allocated NSS action list that has COUNT + actions that matches the array at ACTIONS. */ +nss_action_list __nss_action_allocate (struct nss_action *actions, + size_t count) attribute_hidden; + +/* Returns a pointer to a list allocated by __nss_action_allocate, or + NULL on error. ENOMEM means a (temporary) memory allocation error, + EINVAL means that LINE is syntactically invalid. */ +nss_action_list __nss_action_parse (const char *line); + +/* Called from __libc_freeres. */ +void __nss_action_freeres (void) attribute_hidden; + + +#endif /* _NSS_ACTION_H */ diff --git a/nss/nss_action_parse.c b/nss/nss_action_parse.c new file mode 100644 index 0000000000..ada3acbb08 --- /dev/null +++ b/nss/nss_action_parse.c @@ -0,0 +1,197 @@ +/* Parse a service line from nsswitch.conf. + Copyright (c) 1996-2020 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, see + . */ + +#include "nss_action.h" +#include "nss_module.h" + +#include +#include +#include + +/* Staging area during parsing. */ +#define DYNARRAY_STRUCT action_list +#define DYNARRAY_ELEMENT struct nss_action +#define DYNARRAY_PREFIX action_list_ +#include + + +/* Read the source names: + `( ( "[" "!"? ( "=" )+ "]" )? )*' + */ +static bool +nss_action_parse (const char *line, struct action_list *result) +{ + while (1) + { + while (isspace (line[0])) + ++line; + if (line[0] == '\0') + /* No source specified. */ + return result; + + /* Read identifier. */ + const char *name = line; + while (line[0] != '\0' && !isspace (line[0]) && line[0] != '[') + ++line; + if (name == line) + return true; + + struct nss_action new_service + = { .module = __nss_module_allocate (name, line - name), }; + if (new_service.module == NULL) + { + /* Memory allocation error. */ + action_list_mark_failed (result); + return false; + } + nss_action_set_all (&new_service, NSS_ACTION_CONTINUE); + nss_action_set (&new_service, NSS_STATUS_SUCCESS, NSS_ACTION_RETURN); + nss_action_set (&new_service, NSS_STATUS_RETURN, NSS_ACTION_RETURN); + + while (isspace (line[0])) + ++line; + + if (line[0] == '[') + { + /* Read criterions. */ + do + ++line; + while (line[0] != '\0' && isspace (line[0])); + + do + { + int not; + enum nss_status status; + lookup_actions action; + + /* Grok ! before name to mean all statii but that one. */ + not = line[0] == '!'; + if (not) + ++line; + + /* Read status name. */ + name = line; + while (line[0] != '\0' && !isspace (line[0]) && line[0] != '=' + && line[0] != ']') + ++line; + + /* Compare with known statii. */ + if (line - name == 7) + { + if (__strncasecmp (name, "SUCCESS", 7) == 0) + status = NSS_STATUS_SUCCESS; + else if (__strncasecmp (name, "UNAVAIL", 7) == 0) + status = NSS_STATUS_UNAVAIL; + else + return false; + } + else if (line - name == 8) + { + if (__strncasecmp (name, "NOTFOUND", 8) == 0) + status = NSS_STATUS_NOTFOUND; + else if (__strncasecmp (name, "TRYAGAIN", 8) == 0) + status = NSS_STATUS_TRYAGAIN; + else + return false; + } + else + return false; + + while (isspace (line[0])) + ++line; + if (line[0] != '=') + return false; + do + ++line; + while (isspace (line[0])); + + name = line; + while (line[0] != '\0' && !isspace (line[0]) && line[0] != '=' + && line[0] != ']') + ++line; + + if (line - name == 6 && __strncasecmp (name, "RETURN", 6) == 0) + action = NSS_ACTION_RETURN; + else if (line - name == 8 + && __strncasecmp (name, "CONTINUE", 8) == 0) + action = NSS_ACTION_CONTINUE; + else if (line - name == 5 + && __strncasecmp (name, "MERGE", 5) == 0) + action = NSS_ACTION_MERGE; + else + return false; + + if (not) + { + /* Save the current action setting for this status, + set them all to the given action, and reset this one. */ + const lookup_actions save + = nss_action_get (&new_service, status); + nss_action_set_all (&new_service, action); + nss_action_set (&new_service, status, save); + } + else + nss_action_set (&new_service, status, action); + + /* Skip white spaces. */ + while (isspace (line[0])) + ++line; + } + while (line[0] != ']'); + + /* Skip the ']'. */ + ++line; + } + + action_list_add (result, new_service); + } +} + +nss_action_list + __nss_action_parse (const char *line) +{ + struct action_list 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; + } + else if (action_list_has_failed (&list)) + { + /* Memory allocation error. */ + __set_errno (ENOMEM); + return NULL; + } + else + { + /* Parse error. */ + __set_errno (EINVAL); + return NULL; + } +} From patchwork Thu Jun 25 04:05:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: DJ Delorie X-Patchwork-Id: 39797 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 7C4E6388A80C; Thu, 25 Jun 2020 04:05:45 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7C4E6388A80C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1593057945; bh=RXKnKB1nyrwTMqRHwiYYjvJb+pgH03GtVktScA4VsEE=; h=Date:To:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=igw3weI3tmwi3dYS3Bx8ylOLz+JSzPODZcpug0kXyAjDRd6ziwJINh8hRWsoyZU3x DpdRbyHKy7cl9LFouivgWIwoRAc+Kwe2sG06EytAC6aGa+YCeaN+PPzRb27eKRNPW3 TjDFKNItm8HDXD+6JQhdC1md/Blw4FI7edd3lfFI= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [207.211.31.120]) by sourceware.org (Postfix) with ESMTP id 5E7D5388A80C for ; Thu, 25 Jun 2020 04:05:41 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 5E7D5388A80C Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-397-0CDWALySOZu7k9TE24oUJg-1; Thu, 25 Jun 2020 00:05:23 -0400 X-MC-Unique: 0CDWALySOZu7k9TE24oUJg-1 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id BFAEA464 for ; Thu, 25 Jun 2020 04:05:22 +0000 (UTC) Received: from greed.delorie.com (ovpn-112-186.phx2.redhat.com [10.3.112.186]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 823DA5C541 for ; Thu, 25 Jun 2020 04:05:22 +0000 (UTC) Received: from greed.delorie.com.redhat.com (localhost [127.0.0.1]) by greed.delorie.com (8.14.7/8.14.7) with ESMTP id 05P45LhH023205 for ; Thu, 25 Jun 2020 00:05:21 -0400 Date: Thu, 25 Jun 2020 00:05:21 -0400 Message-Id: To: libc-alpha@sourceware.org Subject: [PATCH 3/4] nss: Implement X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-13.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: DJ Delorie via Libc-alpha From: DJ Delorie Reply-To: DJ Delorie Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" --- nss/Makefile | 2 +- nss/nss_database.c | 424 +++++++++++++++++++++++++++++++++++++++ nss/nss_database.h | 73 +++++++ sysdeps/mach/hurd/fork.c | 8 + sysdeps/nptl/fork.c | 9 + 5 files changed, 515 insertions(+), 1 deletion(-) create mode 100644 nss/nss_database.c create mode 100644 nss/nss_database.h diff --git a/nss/Makefile b/nss/Makefile index 464655d045..194b183c91 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -29,7 +29,7 @@ routines = nsswitch getnssent getnssent_r digits_dots \ valid_field valid_list_field rewrite_field \ $(addsuffix -lookup,$(databases)) \ compat-lookup nss_hash nss_module nss_action \ - nss_action_parse + nss_action_parse nss_database # These are the databases that go through nss dispatch. # Caution: if you add a database here, you must add its real name diff --git a/nss/nss_database.c b/nss/nss_database.c new file mode 100644 index 0000000000..0f6342d0c8 --- /dev/null +++ b/nss/nss_database.c @@ -0,0 +1,424 @@ +/* Mapping NSS services to action lists. + Copyright (C) 1996-2020 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, see + . */ + +#include "nss_database.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct nss_database_state +{ + struct nss_database_data data; + __libc_lock_define (, lock); +}; + +static void *global_place; + +static void * +global_allocate (void *closure) +{ + struct nss_database_state *result = malloc (sizeof (*result)); + if (result != NULL) + { + result->data.nsswitch_conf.size = -1; /* Force reload. */ + memset (result->data.services, 0, sizeof (result->data.services)); + result->data.initialized = true; + result->data.reload_disabled = false; + __libc_lock_init (result->lock); + } + return result; +} + +static struct nss_database_state * +nss_database_state_get (void) +{ + return allocate_once (&global_place, global_allocate, NULL, NULL); +} + +/* Database default selections. nis/compat mappings get turned into + "files" for !LINK_OBSOLETE_NSL configurations. */ +enum nss_database_default +{ + nss_database_default_defconfig = 0, /* "nis [NOTFOUND=return] files". */ + nss_database_default_compat, /* "compat [NOTFOUND=return] files". */ + nss_database_default_dns, /* "dns [!UNAVAIL=return] files". */ + nss_database_default_files, /* "files". */ + nss_database_default_nis, /* "nis". */ + nss_database_default_nis_nisplus, /* "nis nisplus". */ + nss_database_default_none, /* Empty list. */ + + NSS_DATABASE_DEFAULT_COUNT /* Number of defaults. */ +}; + +/* Databases not listed default to nss_database_default_defconfig. */ +static const char per_database_defaults[NSS_DATABASE_COUNT] = + { + [nss_database_group] = nss_database_default_compat, + [nss_database_gshadow] = nss_database_default_files, + [nss_database_hosts] = nss_database_default_dns, + [nss_database_initgroups] = nss_database_default_none, + [nss_database_networks] = nss_database_default_dns, + [nss_database_passwd] = nss_database_default_compat, + [nss_database_publickey] = nss_database_default_nis_nisplus, + [nss_database_shadow] = nss_database_default_compat, + }; + +struct nss_database_default_cache +{ + nss_action_list caches[NSS_DATABASE_DEFAULT_COUNT]; +}; + +static bool +nss_database_select_default (struct nss_database_default_cache *cache, + enum nss_database db, nss_action_list *result) +{ + enum nss_database_default def = per_database_defaults[db]; + *result = cache->caches[def]; + if (*result != NULL) + return true; + + /* Determine the default line string. */ + const char *line; + switch (def) + { +#ifdef LINK_OBSOLETE_NSL + case nss_database_default_defconfig: + line = "nis [NOTFOUND=return] files"; + break; + case nss_database_default_compat: + line = "compat [NOTFOUND=return] files"; + break; +#endif + + case nss_database_default_dns: + line = "dns [!UNAVAIL=return] files"; + break; + + case nss_database_default_files: +#ifndef LINK_OBSOLETE_NSL + case nss_database_default_defconfig: + case nss_database_default_compat: +#endif + line = "files"; + break; + + case nss_database_default_nis: + line = "nis"; + break; + + case nss_database_default_nis_nisplus: + line = "nis nisplus"; + break; + + case nss_database_default_none: + /* Very special case: Leave *result as NULL. */ + return true; + + case NSS_DATABASE_DEFAULT_COUNT: + __builtin_unreachable (); + } + if (def < 0 || def >= NSS_DATABASE_DEFAULT_COUNT) + /* Tell GCC that line is initialized. */ + __builtin_unreachable (); + + *result = __nss_action_parse (line); + if (*result == NULL) + { + assert (errno == ENOMEM); + return false; + } + else + return true; +} + +/* database_name must be large enough for each individual name plus a + null terminator. */ +typedef char database_name[11]; +#define DEFINE_DATABASE(name) \ + _Static_assert (sizeof (#name) <= sizeof (database_name), #name); +#include "databases.def" +#undef DEFINE_DATABASE + +static const database_name nss_database_name_array[] = + { +#define DEFINE_DATABASE(name) #name, +#include "databases.def" +#undef DEFINE_DATABASE + }; + +static int +name_search (const void *left, const void *right) +{ + return strcmp (left, right); +} + +static int +name_to_database_index (const char *name) +{ + database_name *name_entry = bsearch (name, nss_database_name_array, + array_length (nss_database_name_array), + sizeof (database_name), name_search); + if (name_entry == NULL) + return -1; + return name_entry - nss_database_name_array; +} + +static bool +process_line (struct nss_database_data *data, char *line) +{ + /* Ignore leading white spaces. ATTENTION: this is different from + what is implemented in Solaris. The Solaris man page says a line + beginning with a white space character is ignored. We regard + this as just another misfeature in Solaris. */ + while (isspace (line[0])) + ++line; + + /* Recognize ` ":"'. */ + char *name = line; + while (line[0] != '\0' && !isspace (line[0]) && line[0] != ':') + ++line; + if (line[0] == '\0' || name == line) + /* Syntax error. Skip this line. */ + return true; + *line++ = '\0'; + + int db = name_to_database_index (name); + if (db < 0) + /* Not our database (e.g., sudoers). */ + return true; + + nss_action_list result = __nss_action_parse (line); + if (result == NULL) + return false; + data->services[db] = result; + return true; +} + +/* Iterate over the lines in FP, parse them, and store them in DATA. + Return false on memory allocation failure, true on success. */ +static bool +nss_database_reload_1 (struct nss_database_data *data, FILE *fp) +{ + char *line = NULL; + size_t line_allocated = 0; + bool result = false; + + while (true) + { + ssize_t ret = __getline (&line, &line_allocated, fp); + if (ferror_unlocked (fp)) + break; + if (feof_unlocked (fp)) + { + result = true; + break; + } + assert (ret > 0); + (void) ret; /* For NDEBUG builds. */ + + if (!process_line (data, line)) + break; + } + + free (line); + return result; +} + +static bool +nss_database_reload (struct nss_database_data *staging, + struct file_change_detection *initial) +{ + FILE *fp = fopen (_PATH_NSSWITCH_CONF, "rce"); + if (fp == NULL) + switch (errno) + { + case EACCES: + case EISDIR: + case ELOOP: + case ENOENT: + case ENOTDIR: + case EPERM: + /* Ignore these errors. They are persistent errors caused + by file system contents. */ + break; + default: + /* Other errors refer to resource allocation problems and + need to be handled by the application. */ + return false; + } + else + /* No other threads have access to fp. */ + __fsetlocking (fp, FSETLOCKING_BYCALLER); + + bool ok = true; + if (fp != NULL) + ok = nss_database_reload_1 (staging, fp); + + /* Apply defaults. */ + if (ok) + { + struct nss_database_default_cache cache = { }; + for (int i = 0; i < NSS_DATABASE_COUNT; ++i) + if (staging->services[i] == NULL) + { + ok = nss_database_select_default (&cache, i, + &staging->services[i]); + if (!ok) + break; + } + } + + if (ok) + ok = __file_change_detection_for_fp (&staging->nsswitch_conf, fp); + + if (fp != NULL) + { + int saved_errno = errno; + fclose (fp); + __set_errno (saved_errno); + } + + if (ok && !__file_is_unchanged (&staging->nsswitch_conf, initial)) + /* Reload is required because the file changed while reading. */ + staging->nsswitch_conf.size = -1; + + return ok; +} + +static bool +nss_database_check_reload_and_get (struct nss_database_state *local, + nss_action_list *result, + enum nss_database database_index) +{ + /* Acquire MO is needed because the thread that sets reload_disabled + 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; + + struct file_change_detection initial; + if (!__file_change_detection_for_path (&initial, _PATH_NSSWITCH_CONF)) + return false; + + __libc_lock_lock (local->lock); + if (__file_is_unchanged (&initial, &local->data.nsswitch_conf)) + { + /* Configuration is up-to-date. Read it and return it to the + caller. */ + *result = local->data.services[database_index]; + __libc_lock_unlock (local->lock); + return true; + } + __libc_lock_unlock (local->lock); + + /* Avoid overwriting the global configuration until we have loaded + everything successfully. Otherwise, if the file change + information changes back to what is in the global configuration, + the lookups would use the partially-written configuration. */ + struct nss_database_data staging = { .initialized = true, }; + + bool ok = nss_database_reload (&staging, &initial); + + if (ok) + { + __libc_lock_lock (local->lock); + + /* See above for memory order. */ + if (!atomic_load_acquire (&local->data.reload_disabled)) + /* This may go back in time if another thread beats this + thread with the update, but in this case, a reload happens + on the next NSS call. */ + local->data = staging; + + *result = local->data.services[database_index]; + __libc_lock_unlock (local->lock); + } + + return ok; +} + +bool +__nss_database_get (enum nss_database db, nss_action_list *actions) +{ + struct nss_database_state *local = nss_database_state_get (); + return nss_database_check_reload_and_get (local, actions, db); +} + +nss_action_list +__nss_database_get_noreload (enum nss_database db) +{ + /* There must have been a previous __nss_database_get call. */ + struct nss_database_state *local = atomic_load_acquire (&global_place); + assert (local != NULL); + + __libc_lock_lock (local->lock); + nss_action_list result = local->data.services[db]; + __libc_lock_unlock (local->lock); + return result; +} + +void __libc_freeres_fn_section +__nss_database_freeres (void) +{ + free (global_place); + global_place = NULL; +} + +void +__nss_database_fork_prepare_parent (struct nss_database_data *data) +{ + /* Do not use allocate_once to trigger loading unnecessarily. */ + struct nss_database_state *local = atomic_load_acquire (&global_place); + if (local == NULL) + data->initialized = false; + else + { + /* Make a copy of the configuration. This approach was chosen + because it avoids acquiring the lock during the actual + fork. */ + __libc_lock_lock (local->lock); + *data = local->data; + __libc_lock_unlock (local->lock); + } +} + +void +__nss_database_fork_subprocess (struct nss_database_data *data) +{ + struct nss_database_state *local = atomic_load_acquire (&global_place); + if (data->initialized) + { + /* Restore the state at the point of the fork. */ + assert (local != NULL); + local->data = *data; + __libc_lock_init (local->lock); + } + else if (local != NULL) + /* The NSS configuration was loaded concurrently during fork. We + do not know its state, so we need to discard it. */ + global_place = NULL; +} diff --git a/nss/nss_database.h b/nss/nss_database.h new file mode 100644 index 0000000000..a157bbdbb0 --- /dev/null +++ b/nss/nss_database.h @@ -0,0 +1,73 @@ +/* Mapping NSS services to action lists. + Copyright (C) 2020 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, see + . */ + +#ifndef _NSS_DATABASE_H +#define _NSS_DATABASE_H + +#include + +#include "nss_action.h" + +/* The enumeration literal in enum nss_database for the database NAME + (e.g., nss_database_hosts for hosts). */ +#define NSS_DATABASE_LITERAL(name) nss_database_##name + +enum nss_database +{ +#define DEFINE_DATABASE(name) NSS_DATABASE_LITERAL (name), +#include "databases.def" +#undef DEFINE_DATABASE + + /* Total number of databases. */ + NSS_DATABASE_COUNT +}; + + +/* Looks up the action list for DB and stores it in *ACTIONS. Returns + true on success or false on failure. Success can mean that + *ACTIONS is NULL. */ +bool __nss_database_get (enum nss_database db, nss_action_list *actions) + attribute_hidden; + +/* Like __nss_database_get, but does not reload /etc/nsswitch.conf + from disk. This assumes that there has been a previous successful + __nss_database_get call (which may not have returned any data). */ +nss_action_list __nss_database_get_noreload (enum nss_database db) + attribute_hidden; + +/* Called from __libc_freeres. */ +void __nss_database_freeres (void) attribute_hidden; + +/* Internal type. Exposed only for fork handling purposes. */ +struct nss_database_data +{ + struct file_change_detection nsswitch_conf; + nss_action_list services[NSS_DATABASE_COUNT]; + int reload_disabled; /* Actually bool; int for atomic access. */ + bool initialized; +}; + +/* Called by fork in the parent process, before forking. */ +void __nss_database_fork_prepare_parent (struct nss_database_data *data) + attribute_hidden; + +/* Called by fork in the new subprocess, after forking. */ +void __nss_database_fork_subprocess (struct nss_database_data *data) + attribute_hidden; + +#endif /* _NSS_DATABASE_H */ diff --git a/sysdeps/mach/hurd/fork.c b/sysdeps/mach/hurd/fork.c index 32783069ec..1aec951e76 100644 --- a/sysdeps/mach/hurd/fork.c +++ b/sysdeps/mach/hurd/fork.c @@ -28,6 +28,7 @@ #include "hurdmalloc.h" /* XXX */ #include #include +#include #undef __fork @@ -68,6 +69,7 @@ __fork (void) size_t i; error_t err; struct hurd_sigstate *volatile ss; + struct nss_database_data nss_database_data; RUN_HOOK (_hurd_atfork_prepare_hook, ()); @@ -109,6 +111,9 @@ __fork (void) /* Run things that prepare for forking before we create the task. */ RUN_HOOK (_hurd_fork_prepare_hook, ()); + call_function_static_weak (__nss_database_fork_prepare_parent, + &nss_database_data); + /* Lock things that want to be locked before we fork. */ { void *const *p; @@ -666,6 +671,9 @@ __fork (void) _hurd_malloc_fork_child (); call_function_static_weak (__malloc_fork_unlock_child); + call_function_static_weak (__nss_database_fork_subprocess, + &nss_database_data); + /* Run things that want to run in the child task to set up. */ RUN_HOOK (_hurd_fork_child_hook, ()); diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c index 5091a000e3..964eb1e5a8 100644 --- a/sysdeps/nptl/fork.c +++ b/sysdeps/nptl/fork.c @@ -32,6 +32,7 @@ #include #include #include +#include static void fresetlockfiles (void) @@ -57,6 +58,8 @@ __libc_fork (void) __run_fork_handlers (atfork_run_prepare, multiple_threads); + struct nss_database_data nss_database_data; + /* If we are not running multiple threads, we do not have to preserve lock state. If fork runs from a signal handler, only async-signal-safe functions can be used in the child. These data @@ -64,6 +67,9 @@ __libc_fork (void) not matter if fork was called from a signal handler. */ if (multiple_threads) { + call_function_static_weak (__nss_database_fork_prepare_parent, + &nss_database_data); + _IO_list_lock (); /* Acquire malloc locks. This needs to come last because fork @@ -118,6 +124,9 @@ __libc_fork (void) /* Reset locks in the I/O code. */ _IO_list_resetlock (); + + call_function_static_weak (__nss_database_fork_subprocess, + &nss_database_data); } /* Reset the lock the dynamic loader uses to protect its data. */ From patchwork Thu Jun 25 04:05:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: DJ Delorie X-Patchwork-Id: 39798 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 82CCC3892465; Thu, 25 Jun 2020 04:05:49 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 82CCC3892465 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1593057949; bh=6J59Ysqbg1fxSFma+fbJHXpZmgwOV9V+r+xzB2QxxHQ=; h=Date:To:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=QkFY9l2R9YCW8Ae0J8xg4qqwdElFTqKqVgWa6nGzT3X8mLY614m8yuIk4OLzoHiFy evUO5rLS1rSiz2RWZZN5HLYmbo8A34Nm8lQEmKFJPZIPuDRmAO1J0LLqq7yia0iVa8 BkRkZD3wBV97OSF/T/k0/Amtmq92T2UMzCK06cIk= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [207.211.31.120]) by sourceware.org (Postfix) with ESMTP id 822DF3892462 for ; Thu, 25 Jun 2020 04:05:42 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 822DF3892462 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-109-iRbFLYaGPy6LO_pFcEE4ew-1; Thu, 25 Jun 2020 00:05:39 -0400 X-MC-Unique: iRbFLYaGPy6LO_pFcEE4ew-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 73C4F107ACF2 for ; Thu, 25 Jun 2020 04:05:38 +0000 (UTC) Received: from greed.delorie.com (ovpn-112-186.phx2.redhat.com [10.3.112.186]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 119702B4B0 for ; Thu, 25 Jun 2020 04:05:37 +0000 (UTC) Received: from greed.delorie.com.redhat.com (localhost [127.0.0.1]) by greed.delorie.com (8.14.7/8.14.7) with ESMTP id 05P45bMR023209 for ; Thu, 25 Jun 2020 00:05:37 -0400 Date: Thu, 25 Jun 2020 00:05:37 -0400 Message-Id: To: libc-alpha@sourceware.org Subject: [PATCH 4/4] nsswitch: use new internal API X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-13.4 required=5.0 tests=BAYES_00, DKIM_INVALID, DKIM_SIGNED, GIT_PATCH_0, KAM_DMARC_STATUS, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: DJ Delorie via Libc-alpha From: DJ Delorie Reply-To: DJ Delorie Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" Stitch new ABI and types throughout all NSS callers and providers. --- grp/compat-initgroups.c | 2 +- grp/initgroups.c | 41 +- inet/ether_hton.c | 21 +- inet/ether_ntoh.c | 21 +- inet/getnetgrent_r.c | 40 +- inet/netgroup.h | 2 +- malloc/set-freeres.c | 4 +- nscd/aicache.c | 17 +- nscd/gai.c | 2 +- nscd/initgrcache.c | 8 +- nscd/netgroupcache.c | 4 +- nscd/nscd_netgroup.c | 2 +- nss/XXX-lookup.c | 2 +- nss/compat-lookup.c | 8 +- nss/getXXbyYY_r.c | 10 +- nss/getXXent_r.c | 10 +- nss/getnssent_r.c | 22 +- nss/nss_action.c | 2 +- nss/nss_action_parse.c | 22 +- nss/nss_compat/compat-grp.c | 2 +- nss/nss_compat/compat-initgroups.c | 2 +- nss/nss_compat/compat-pwd.c | 2 +- nss/nss_compat/compat-spwd.c | 2 +- nss/nss_database.c | 40 +- nss/nss_module.c | 107 +++- nss/nsswitch.c | 817 ++--------------------------- nss/nsswitch.h | 40 +- posix/tst-rfc3484-2.c | 2 +- posix/tst-rfc3484-3.c | 2 +- posix/tst-rfc3484.c | 2 +- sunrpc/netname.c | 21 +- sunrpc/publickey.c | 42 +- sysdeps/posix/getaddrinfo.c | 9 +- 33 files changed, 299 insertions(+), 1031 deletions(-) diff --git a/grp/compat-initgroups.c b/grp/compat-initgroups.c index 3dd50d2306..9df940767b 100644 --- a/grp/compat-initgroups.c +++ b/grp/compat-initgroups.c @@ -10,7 +10,7 @@ typedef enum nss_status (*get_function) (struct group *, char *, static enum nss_status -compat_call (service_user *nip, const char *user, gid_t group, long int *start, +compat_call (nss_action_list nip, const char *user, gid_t group, long int *start, long int *size, gid_t **groupsp, long int limit, int *errnop) { struct group grpbuf; diff --git a/grp/initgroups.c b/grp/initgroups.c index f4c4e986e9..88eb853496 100644 --- a/grp/initgroups.c +++ b/grp/initgroups.c @@ -69,7 +69,6 @@ internal_getgrouplist (const char *user, gid_t group, long int *size, #endif enum nss_status status = NSS_STATUS_UNAVAIL; - int no_more = 0; /* Never store more than the starting *SIZE number of elements. */ assert (*size > 0); @@ -77,33 +76,28 @@ internal_getgrouplist (const char *user, gid_t group, long int *size, /* Start is one, because we have the first group as parameter. */ long int start = 1; - if (__nss_initgroups_database == NULL) - { - if (__nss_database_lookup2 ("initgroups", NULL, "", - &__nss_initgroups_database) < 0) - { - if (__nss_group_database == NULL) - no_more = __nss_database_lookup2 ("group", NULL, DEFAULT_CONFIG, - &__nss_group_database); + nss_action_list nip; - __nss_initgroups_database = __nss_group_database; - } - else - use_initgroups_entry = true; + if (__nss_database_get (nss_database_initgroups, &nip)) + { + use_initgroups_entry = true; + } + else if (__nss_database_get (nss_database_group, &nip)) + { + use_initgroups_entry = false; } else - /* __nss_initgroups_database might have been set through - __nss_configure_lookup in which case use_initgroups_entry was - not set here. */ - use_initgroups_entry = __nss_initgroups_database != __nss_group_database; + { + nip = __nss_action_parse (DEFAULT_CONFIG); + use_initgroups_entry = false; + } - service_user *nip = __nss_initgroups_database; - while (! no_more) + while (nip && nip->module) { long int prev_start = start; - initgroups_dyn_function fct = __nss_lookup_function (nip, - "initgroups_dyn"); + initgroups_dyn_function fct = __nss_lookup_function (nip, "initgroups_dyn"); + if (fct == NULL) status = compat_call (nip, user, group, &start, size, groupsp, limit, &errno); @@ -140,10 +134,7 @@ internal_getgrouplist (const char *user, gid_t group, long int *size, && nss_next_action (nip, status) == NSS_ACTION_RETURN) break; - if (nip->next == NULL) - no_more = -1; - else - nip = nip->next; + nip ++; } return start; diff --git a/inet/ether_hton.c b/inet/ether_hton.c index ff6943fc35..cccae17f10 100644 --- a/inet/ether_hton.c +++ b/inet/ether_hton.c @@ -30,9 +30,7 @@ typedef int (*lookup_function) (const char *, struct etherent *, char *, int, int ether_hostton (const char *hostname, struct ether_addr *addr) { - static service_user *startp; - static lookup_function start_fct; - service_user *nip; + nss_action_list nip; union { lookup_function f; @@ -42,22 +40,7 @@ ether_hostton (const char *hostname, struct ether_addr *addr) enum nss_status status = NSS_STATUS_UNAVAIL; struct etherent etherent; - if (startp == NULL) - { - no_more = __nss_ethers_lookup2 (&nip, "gethostton_r", NULL, &fct.ptr); - if (no_more) - startp = (service_user *) -1; - else - { - startp = nip; - start_fct = fct.f; - } - } - else - { - fct.f = start_fct; - no_more = (nip = startp) == (service_user *) -1; - } + no_more = __nss_ethers_lookup2 (&nip, "gethostton_r", NULL, &fct.ptr); while (no_more == 0) { diff --git a/inet/ether_ntoh.c b/inet/ether_ntoh.c index e409773601..5ef654292c 100644 --- a/inet/ether_ntoh.c +++ b/inet/ether_ntoh.c @@ -31,9 +31,7 @@ typedef int (*lookup_function) (const struct ether_addr *, struct etherent *, int ether_ntohost (char *hostname, const struct ether_addr *addr) { - static service_user *startp; - static lookup_function start_fct; - service_user *nip; + nss_action_list nip; union { lookup_function f; @@ -43,22 +41,7 @@ ether_ntohost (char *hostname, const struct ether_addr *addr) enum nss_status status = NSS_STATUS_UNAVAIL; struct etherent etherent; - if (startp == NULL) - { - no_more = __nss_ethers_lookup2 (&nip, "getntohost_r", NULL, &fct.ptr); - if (no_more) - startp = (service_user *) -1; - else - { - startp = nip; - start_fct = fct.f; - } - } - else - { - fct.f = start_fct; - no_more = (nip = startp) == (service_user *) -1; - } + no_more = __nss_ethers_lookup2 (&nip, "getntohost_r", NULL, &fct.ptr); while (no_more == 0) { diff --git a/inet/getnetgrent_r.c b/inet/getnetgrent_r.c index 78a66eee00..9c75af6f77 100644 --- a/inet/getnetgrent_r.c +++ b/inet/getnetgrent_r.c @@ -39,40 +39,12 @@ static struct __netgrent dataset; /* Set up NIP to run through the services. Return nonzero if there are no services (left). */ static int -setup (void **fctp, service_user **nipp) +setup (void **fctp, nss_action_list *nipp) { - /* Remember the first service_entry, it's always the same. */ - static bool startp_initialized; - static service_user *startp; int no_more; - if (!startp_initialized) - { - /* Executing this more than once at the same time must yield the - same result every time. So we need no locking. */ - no_more = __nss_netgroup_lookup2 (nipp, "setnetgrent", NULL, fctp); - startp = no_more ? (service_user *) -1 : *nipp; -#ifdef PTR_MANGLE - PTR_MANGLE (startp); -#endif - atomic_write_barrier (); - startp_initialized = true; - } - else - { - service_user *nip = startp; -#ifdef PTR_DEMANGLE - PTR_DEMANGLE (nip); -#endif - if (nip == (service_user *) -1) - /* No services at all. */ - return 1; - - /* Reset to the beginning of the service list. */ - *nipp = nip; - /* Look up the first function. */ - no_more = __nss_lookup (nipp, "setnetgrent", NULL, fctp); - } + no_more = __nss_netgroup_lookup2 (nipp, "setnetgrent", NULL, fctp); + return no_more; } @@ -100,7 +72,7 @@ endnetgrent_hook (struct __netgrent *datap) { enum nss_status (*endfct) (struct __netgrent *); - if (datap->nip == NULL || datap->nip == (service_user *) -1l) + if (datap->nip == NULL || datap->nip == (nss_action_list) -1l) return; endfct = __nss_lookup_function (datap->nip, "endnetgrent"); @@ -133,7 +105,7 @@ __internal_setnetgrent_reuse (const char *group, struct __netgrent *datap, /* Ignore status, we force check in `__nss_next2'. */ status = DL_CALL_FCT (*fct.f, (group, datap)); - service_user *old_nip = datap->nip; + nss_action_list old_nip = datap->nip; no_more = __nss_next2 (&datap->nip, "setnetgrent", NULL, &fct.ptr, status, 0); @@ -275,7 +247,7 @@ __internal_getnetgrent_r (char **hostp, char **userp, char **domainp, /* This bogus function pointer is a special marker left by __nscd_setnetgrent to tell us to use the data it left before considering any modules. */ - if (datap->nip == (service_user *) -1l) + if (datap->nip == (nss_action_list) -1l) fct = nscd_getnetgrent; else #endif diff --git a/inet/netgroup.h b/inet/netgroup.h index 53081db78f..910094b9ca 100644 --- a/inet/netgroup.h +++ b/inet/netgroup.h @@ -64,7 +64,7 @@ struct __netgrent /* This handle for the NSS data base is shared between all set/get/endXXXent functions. */ - service_user *nip; + struct nss_action *nip; }; 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 #include -#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/nscd/aicache.c b/nscd/aicache.c index ee9c9b8843..ce3bb382ce 100644 --- a/nscd/aicache.c +++ b/nscd/aicache.c @@ -71,20 +71,15 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) key); } - static service_user *hosts_database; - service_user *nip; + nss_action_list nip; int no_more; int rc6 = 0; int rc4 = 0; int herrno = 0; - if (hosts_database == NULL) - no_more = __nss_database_lookup2 ("hosts", NULL, - "dns [!UNAVAIL=return] files", - &hosts_database); - else - no_more = 0; - nip = hosts_database; + no_more = __nss_database_lookup2 ("hosts", NULL, + "dns [!UNAVAIL=return] files", + &nip); /* Initialize configurations. */ struct resolv_context *ctx = __resolv_context_get (); @@ -442,10 +437,10 @@ next_nip: if (nss_next_action (nip, status[1]) == NSS_ACTION_RETURN) break; - if (nip->next == NULL) + if (nip[1].module == NULL) no_more = -1; else - nip = nip->next; + ++ nip; } /* No result found. Create a negative result record. */ diff --git a/nscd/gai.c b/nscd/gai.c index 2e19530102..aaaddd8fe5 100644 --- a/nscd/gai.c +++ b/nscd/gai.c @@ -43,4 +43,4 @@ #include /* Some variables normally defined in libc. */ -service_user *__nss_hosts_database attribute_hidden; +nss_action_list __nss_hosts_database attribute_hidden; diff --git a/nscd/initgrcache.c b/nscd/initgrcache.c index a9f230bfb0..03cc52368e 100644 --- a/nscd/initgrcache.c +++ b/nscd/initgrcache.c @@ -83,8 +83,8 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req, dbg_log (_("Reloading \"%s\" in group cache!"), (char *) key); } - static service_user *group_database; - service_user *nip; + static nss_action_list group_database; + nss_action_list nip; int no_more; if (group_database == NULL) @@ -167,10 +167,10 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req, && nss_next_action (nip, status) == NSS_ACTION_RETURN) break; - if (nip->next == NULL) + if (nip[1].module == NULL) no_more = -1; else - nip = nip->next; + ++ nip; } bool all_written; diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c index 88c69d1e9c..67be24e837 100644 --- a/nscd/netgroupcache.c +++ b/nscd/netgroupcache.c @@ -124,7 +124,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, dbg_log (_("Reloading \"%s\" in netgroup cache!"), key); } - static service_user *netgroup_database; + static nss_action_list netgroup_database; time_t timeout; struct dataset *dataset; bool cacheable = false; @@ -175,7 +175,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, void *ptr; } setfct; - service_user *nip = netgroup_database; + nss_action_list nip = netgroup_database; int no_more = __nss_lookup (&nip, "setnetgrent", NULL, &setfct.ptr); while (!no_more) { diff --git a/nscd/nscd_netgroup.c b/nscd/nscd_netgroup.c index 7b8dc4081a..0ed9c0cda6 100644 --- a/nscd/nscd_netgroup.c +++ b/nscd/nscd_netgroup.c @@ -116,7 +116,7 @@ __nscd_setnetgrent (const char *group, struct __netgrent *datap) datap->data_size = datalen; datap->cursor = respdata; datap->first = 1; - datap->nip = (service_user *) -1l; + datap->nip = (nss_action_list) -1l; datap->known_groups = NULL; datap->needed_groups = NULL; diff --git a/nss/XXX-lookup.c b/nss/XXX-lookup.c index e26c6d7f8b..d291968db3 100644 --- a/nss/XXX-lookup.c +++ b/nss/XXX-lookup.c @@ -53,7 +53,7 @@ #endif int -DB_LOOKUP_FCT (service_user **ni, const char *fct_name, const char *fct2_name, +DB_LOOKUP_FCT (nss_action_list *ni, const char *fct_name, const char *fct2_name, void **fctp) { if (DATABASE_NAME_SYMBOL == NULL diff --git a/nss/compat-lookup.c b/nss/compat-lookup.c index 9af34150bd..07fcc94f58 100644 --- a/nss/compat-lookup.c +++ b/nss/compat-lookup.c @@ -29,7 +29,7 @@ glibc 2.7 and earlier and glibc 2.8 and later, even on i386. */ int attribute_compat_text_section -__nss_passwd_lookup (service_user **ni, const char *fct_name, void **fctp) +__nss_passwd_lookup (nss_action_list *ni, const char *fct_name, void **fctp) { __set_errno (ENOSYS); return -1; @@ -46,11 +46,11 @@ compat_symbol (libc, __nss_hosts_lookup, __nss_hosts_lookup, GLIBC_2_0); /* These functions were exported under a non-GLIBC_PRIVATE version, even though it is not usable externally due to the service_user - type dependency. */ + (now nss_action_list) type dependency. */ int attribute_compat_text_section -__nss_next (service_user **ni, const char *fct_name, void **fctp, int status, +__nss_next (nss_action_list *ni, const char *fct_name, void **fctp, int status, int all_values) { return -1; @@ -60,7 +60,7 @@ compat_symbol (libc, __nss_next, __nss_next, GLIBC_2_0); int attribute_compat_text_section __nss_database_lookup (const char *database, const char *alternate_name, - const char *defconfig, service_user **ni) + const char *defconfig, nss_action_list *ni) { *ni = NULL; return -1; diff --git a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c index e8c9ab1bb3..cbe78e6d66 100644 --- a/nss/getXXbyYY_r.c +++ b/nss/getXXbyYY_r.c @@ -179,7 +179,7 @@ typedef enum nss_status (*lookup_function) (ADD_PARAMS, LOOKUP_TYPE *, char *, EXTRA_PARAMS); /* The lookup function for the first entry of this service. */ -extern int DB_LOOKUP_FCT (service_user **nip, const char *name, +extern int DB_LOOKUP_FCT (nss_action_list *nip, const char *name, const char *name2, void **fctp); libc_hidden_proto (DB_LOOKUP_FCT) @@ -190,9 +190,9 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer, EXTRA_PARAMS) { static bool startp_initialized; - static service_user *startp; + static nss_action_list startp; static lookup_function start_fct; - service_user *nip; + nss_action_list nip; int do_merge = 0; LOOKUP_TYPE mergegrp; char *mergebuf = NULL; @@ -270,7 +270,7 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer, REENTRANT2_NAME_STRING, &fct.ptr); if (no_more) { - void *tmp_ptr = (service_user *) -1l; + void *tmp_ptr = (nss_action_list) -1l; #ifdef PTR_MANGLE PTR_MANGLE (tmp_ptr); #endif @@ -303,7 +303,7 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer, PTR_DEMANGLE (fct.l); PTR_DEMANGLE (nip); #endif - no_more = nip == (service_user *) -1l; + no_more = nip == (nss_action_list) -1l; } while (no_more == 0) diff --git a/nss/getXXent_r.c b/nss/getXXent_r.c index 8b64fcd795..dfcbd01f66 100644 --- a/nss/getXXent_r.c +++ b/nss/getXXent_r.c @@ -95,11 +95,11 @@ /* This handle for the NSS data base is shared between all set/get/endXXXent functions. */ -static service_user *nip; +static nss_action_list nip; /* Remember the last service used since the last call to `endXXent'. */ -static service_user *last_nip; -/* Remember the first service_entry, it's always the same. */ -static service_user *startp; +static nss_action_list last_nip; +/* Remember the first service_entry across set/get/endent. */ +static nss_action_list startp; #ifdef STAYOPEN_TMP /* We need to remember the last `stayopen' flag given by the user @@ -112,7 +112,7 @@ static STAYOPEN_TMP; __libc_lock_define_initialized (static, lock) /* The lookup function for the first entry of this service. */ -extern int DB_LOOKUP_FCT (service_user **nip, const char *name, +extern int DB_LOOKUP_FCT (nss_action_list *nip, const char *name, const char *name2, void **fctp); libc_hidden_proto (DB_LOOKUP_FCT) diff --git a/nss/getnssent_r.c b/nss/getnssent_r.c index 8a366bc7ea..84e977c33b 100644 --- a/nss/getnssent_r.c +++ b/nss/getnssent_r.c @@ -25,20 +25,20 @@ services (left). */ static int setup (const char *func_name, db_lookup_function lookup_fct, - void **fctp, service_user **nip, service_user **startp, int all) + void **fctp, nss_action_list *nip, nss_action_list *startp, int all) { int no_more; - if (*startp == NULL) + if (*startp == NULL || all) { no_more = lookup_fct (nip, func_name, NULL, fctp); - *startp = no_more ? (service_user *) -1l : *nip; + *startp = no_more ? (nss_action_list) -1l : *nip; } - else if (*startp == (service_user *) -1l) + else if (*startp == (nss_action_list) -1l) /* No services at all. */ return 1; else { - if (all || !*nip) + if (!*nip) /* Reset to the beginning of the service list. */ *nip = *startp; /* Look up the first function. */ @@ -49,8 +49,8 @@ setup (const char *func_name, db_lookup_function lookup_fct, void __nss_setent (const char *func_name, db_lookup_function lookup_fct, - service_user **nip, service_user **startp, - service_user **last_nip, int stayopen, int *stayopen_tmp, + nss_action_list *nip, nss_action_list *startp, + nss_action_list *last_nip, int stayopen, int *stayopen_tmp, int res) { union @@ -110,8 +110,8 @@ __nss_setent (const char *func_name, db_lookup_function lookup_fct, void __nss_endent (const char *func_name, db_lookup_function lookup_fct, - service_user **nip, service_user **startp, - service_user **last_nip, int res) + nss_action_list *nip, nss_action_list *startp, + nss_action_list *last_nip, int res) { union { @@ -154,8 +154,8 @@ int __nss_getent_r (const char *getent_func_name, const char *setent_func_name, db_lookup_function lookup_fct, - service_user **nip, service_user **startp, - service_user **last_nip, int *stayopen_tmp, int res, + nss_action_list *nip, nss_action_list *startp, + nss_action_list *last_nip, int *stayopen_tmp, int res, void *resbuf, char *buffer, size_t buflen, void **result, int *h_errnop) { diff --git a/nss/nss_action.c b/nss/nss_action.c index 24f1c5e4f9..91aebb37e8 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 . */ -#include +#include #include #include diff --git a/nss/nss_action_parse.c b/nss/nss_action_parse.c index ada3acbb08..7a80582842 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 . */ -#include "nss_action.h" -#include "nss_module.h" +#include #include #include @@ -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_compat/compat-grp.c b/nss/nss_compat/compat-grp.c index d4f750b95c..5593e075b4 100644 --- a/nss/nss_compat/compat-grp.c +++ b/nss/nss_compat/compat-grp.c @@ -29,7 +29,7 @@ NSS_DECLARE_MODULE_FUNCTIONS (compat) -static service_user *ni; +static nss_action_list ni; static enum nss_status (*setgrent_impl) (int stayopen); static enum nss_status (*getgrnam_r_impl) (const char *name, struct group * grp, char *buffer, diff --git a/nss/nss_compat/compat-initgroups.c b/nss/nss_compat/compat-initgroups.c index 3671bef48b..0ce6141434 100644 --- a/nss/nss_compat/compat-initgroups.c +++ b/nss/nss_compat/compat-initgroups.c @@ -32,7 +32,7 @@ NSS_DECLARE_MODULE_FUNCTIONS (compat) -static service_user *ni; +static nss_action_list ni; static enum nss_status (*initgroups_dyn_impl) (const char *, gid_t, long int *, long int *, gid_t **, long int, int *); diff --git a/nss/nss_compat/compat-pwd.c b/nss/nss_compat/compat-pwd.c index 394e39b811..8145fc2707 100644 --- a/nss/nss_compat/compat-pwd.c +++ b/nss/nss_compat/compat-pwd.c @@ -33,7 +33,7 @@ NSS_DECLARE_MODULE_FUNCTIONS (compat) -static service_user *ni; +static nss_action_list ni; static enum nss_status (*setpwent_impl) (int stayopen); static enum nss_status (*getpwnam_r_impl) (const char *name, struct passwd * pwd, char *buffer, diff --git a/nss/nss_compat/compat-spwd.c b/nss/nss_compat/compat-spwd.c index ec5bf283cd..08dff30a59 100644 --- a/nss/nss_compat/compat-spwd.c +++ b/nss/nss_compat/compat-spwd.c @@ -33,7 +33,7 @@ NSS_DECLARE_MODULE_FUNCTIONS (compat) -static service_user *ni; +static nss_action_list ni; static enum nss_status (*setspent_impl) (int stayopen); static enum nss_status (*getspnam_r_impl) (const char *name, struct spwd * sp, char *buffer, size_t buflen, diff --git a/nss/nss_database.c b/nss/nss_database.c index 0f6342d0c8..d82e9f9c7e 100644 --- a/nss/nss_database.c +++ b/nss/nss_database.c @@ -217,6 +217,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 @@ -317,8 +350,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 29dc1139c6..702c70e7ab 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 . */ -#include +#include +#include +#include #include #include @@ -29,6 +31,14 @@ #include #include +#ifdef LINK_OBSOLETE_NSL +# define DEFAULT_CONFIG "compat [NOTFOUND=return] files" +# define DEFAULT_DEFCONFIG "nis [NOTFOUND=return] files" +#else +# define DEFAULT_CONFIG "files" +# define DEFAULT_DEFCONFIG "files" +#endif + /* Suffix after .so of NSS service modules. */ static const char *const __nss_shlib_revision = LIBNSS_FILES_SO + 15; @@ -42,6 +52,13 @@ static struct nss_module *nss_module_list; modules. */ __libc_lock_define (static, nss_module_list_lock); +#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 + struct nss_module * __nss_module_allocate (const char *name, size_t name_length) { @@ -218,6 +235,34 @@ module_load (struct nss_module *module) #endif } +# ifdef USE_NSCD + if (is_nscd) + { + /* Call the init function when nscd is used. */ + size_t initlen = (5 + strlen (module->name) + + strlen ("_init") + 1); + char init_name[initlen]; + + /* Construct the init function name. */ + __stpcpy (__stpcpy (__stpcpy (init_name, + "_nss_"), + module->name), + "_init"); + + /* Find the optional init function. */ + void (*ifct) (void (*) (size_t, struct traced_file *)) + = __libc_dlsym (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 + /* Intall the function pointers, following the double-checked locking idiom. Delay this after all processing, in case loading the module triggers unwinding. */ @@ -283,6 +328,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 319e22c3fc..9b73296c5f 100644 --- a/nss/nsswitch.c +++ b/nss/nsswitch.c @@ -32,6 +32,7 @@ #include #include #include +#include #if !defined DO_STATIC_NSS || defined SHARED # include @@ -42,44 +43,20 @@ #include #include -#ifdef LINK_OBSOLETE_NSL -# define DEFAULT_CONFIG "compat [NOTFOUND=return] files" -# define DEFAULT_DEFCONFIG "nis [NOTFOUND=return] files" -#else -# define DEFAULT_CONFIG "files" -# define DEFAULT_DEFCONFIG "files" -#endif - -/* 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. */ @@ -87,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 ?: DEFAULT_DEFCONFIG); - 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) @@ -192,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); @@ -201,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) @@ -219,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) @@ -241,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) @@ -254,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 - { - /* Get the desired function. */ - size_t namlen = (5 + strlen (ni->name) + 1 - + strlen (fct_name) + 1); - char name[namlen]; - - /* Construct the function name. */ - __stpcpy (__stpcpy (__stpcpy (__stpcpy (name, "_nss_"), - ni->name), - "_"), - fct_name); - - /* Look up the symbol. */ - result = __libc_dlsym (ni->library->lib_handle, name); - } -#else - /* We can't get function address dynamically in static linking. */ - { -# define DEFINE_ENT(h,nm) \ - { #h"_get"#nm"ent_r", _nss_##h##_get##nm##ent_r }, \ - { #h"_end"#nm"ent", _nss_##h##_end##nm##ent }, \ - { #h"_set"#nm"ent", _nss_##h##_set##nm##ent }, -# define DEFINE_GET(h,nm) \ - { #h"_get"#nm"_r", _nss_##h##_get##nm##_r }, -# define DEFINE_GETBY(h,nm,ky) \ - { #h"_get"#nm"by"#ky"_r", _nss_##h##_get##nm##by##ky##_r }, - static struct fct_tbl { const char *fname; void *fp; } *tp, tbl[] = - { -# include "function.def" - { NULL, NULL } - }; - size_t namlen = (5 + strlen (ni->name) + 1 - + strlen (fct_name) + 1); - char name[namlen]; - - /* Construct the function name. */ - __stpcpy (__stpcpy (__stpcpy (name, ni->name), - "_"), - fct_name); - - result = NULL; - for (tp = &tbl[0]; tp->fname; tp++) - if (strcmp (tp->fname, name) == 0) - { - result = tp->fp; - break; - } - } -#endif - - /* Remember function pointer for later calls. Even if null, we - record it so a second try needn't search the library again. */ - known->fct_ptr = result; -#ifdef PTR_MANGLE - PTR_MANGLE (known->fct_ptr); -#endif - } - } - - /* Remove the lock. */ - __libc_lock_unlock (lock); - - return result; -} -libc_hidden_def (__nss_lookup_function) - - -static name_database * -nss_parse_file (const char *fname) +__nss_lookup_function (nss_action_list ni, const char *fct_name) { - FILE *fp; - name_database *result; - name_database_entry *last; - char *line; - size_t len; - - /* Open the configuration file. */ - fp = fopen (fname, "rce"); - if (fp == NULL) + if (ni->module == NULL) return NULL; - - /* No threads use this stream. */ - __fsetlocking (fp, FSETLOCKING_BYCALLER); - - result = (name_database *) malloc (sizeof (name_database)); - if (result == NULL) - { - fclose (fp); - return NULL; - } - - result->entry = NULL; - result->library = NULL; - last = NULL; - line = NULL; - len = 0; - do - { - name_database_entry *this; - ssize_t n; - - n = __getline (&line, &len, fp); - if (n < 0) - break; - if (line[n - 1] == '\n') - line[n - 1] = '\0'; - - /* Because the file format does not know any form of quoting we - can search forward for the next '#' character and if found - make it terminating the line. */ - *__strchrnul (line, '#') = '\0'; - - /* If the line is blank it is ignored. */ - if (line[0] == '\0') - continue; - - /* Each line completely specifies the actions for a database. */ - this = nss_getline (line); - if (this != NULL) - { - if (last != NULL) - last->next = this; - else - result->entry = this; - - last = this; - } - } - while (!__feof_unlocked (fp)); - - /* Free the buffer. */ - free (line); - /* Close configuration file. */ - fclose (fp); - - return result; -} - - -/* Read the source names: - `( ( "[" "!"? ( "=" )+ "]" )? )*' - */ -static service_user * -nss_parse_service_list (const char *line) -{ - service_user *result = NULL, **nextp = &result; - - while (1) - { - service_user *new_service; - const char *name; - - while (isspace (line[0])) - ++line; - if (line[0] == '\0') - /* No source specified. */ - return result; - - /* Read identifier. */ - name = line; - while (line[0] != '\0' && !isspace (line[0]) && line[0] != '[') - ++line; - if (name == line) - return result; - - - new_service = (service_user *) malloc (sizeof (service_user) - + (line - name + 1)); - if (new_service == NULL) - return result; - - *((char *) __mempcpy (new_service->name, name, line - name)) = '\0'; - - /* Set default actions. */ - new_service->actions[2 + NSS_STATUS_TRYAGAIN] = NSS_ACTION_CONTINUE; - new_service->actions[2 + NSS_STATUS_UNAVAIL] = NSS_ACTION_CONTINUE; - new_service->actions[2 + NSS_STATUS_NOTFOUND] = NSS_ACTION_CONTINUE; - new_service->actions[2 + NSS_STATUS_SUCCESS] = NSS_ACTION_RETURN; - new_service->actions[2 + NSS_STATUS_RETURN] = NSS_ACTION_RETURN; - new_service->library = NULL; - new_service->known = NULL; - new_service->next = NULL; - - while (isspace (line[0])) - ++line; - - if (line[0] == '[') - { - /* Read criterions. */ - do - ++line; - while (line[0] != '\0' && isspace (line[0])); - - do - { - int not; - enum nss_status status; - lookup_actions action; - - /* Grok ! before name to mean all statii but that one. */ - not = line[0] == '!'; - if (not) - ++line; - - /* Read status name. */ - name = line; - while (line[0] != '\0' && !isspace (line[0]) && line[0] != '=' - && line[0] != ']') - ++line; - - /* Compare with known statii. */ - if (line - name == 7) - { - if (__strncasecmp (name, "SUCCESS", 7) == 0) - status = NSS_STATUS_SUCCESS; - else if (__strncasecmp (name, "UNAVAIL", 7) == 0) - status = NSS_STATUS_UNAVAIL; - else - goto finish; - } - else if (line - name == 8) - { - if (__strncasecmp (name, "NOTFOUND", 8) == 0) - status = NSS_STATUS_NOTFOUND; - else if (__strncasecmp (name, "TRYAGAIN", 8) == 0) - status = NSS_STATUS_TRYAGAIN; - else - goto finish; - } - else - goto finish; - - while (isspace (line[0])) - ++line; - if (line[0] != '=') - goto finish; - do - ++line; - while (isspace (line[0])); - - name = line; - while (line[0] != '\0' && !isspace (line[0]) && line[0] != '=' - && line[0] != ']') - ++line; - - if (line - name == 6 && __strncasecmp (name, "RETURN", 6) == 0) - action = NSS_ACTION_RETURN; - else if (line - name == 8 - && __strncasecmp (name, "CONTINUE", 8) == 0) - action = NSS_ACTION_CONTINUE; - else if (line - name == 5 - && __strncasecmp (name, "MERGE", 5) == 0) - action = NSS_ACTION_MERGE; - else - goto finish; - - if (not) - { - /* Save the current action setting for this status, - set them all to the given action, and reset this one. */ - const lookup_actions save = new_service->actions[2 + status]; - new_service->actions[2 + NSS_STATUS_TRYAGAIN] = action; - new_service->actions[2 + NSS_STATUS_UNAVAIL] = action; - new_service->actions[2 + NSS_STATUS_NOTFOUND] = action; - new_service->actions[2 + NSS_STATUS_SUCCESS] = action; - new_service->actions[2 + status] = save; - } - else - new_service->actions[2 + status] = action; - - /* Skip white spaces. */ - while (isspace (line[0])) - ++line; - } - while (line[0] != ']'); - - /* Skip the ']'. */ - ++line; - } - - *nextp = new_service; - nextp = &new_service->next; - continue; - - finish: - free (new_service); - return result; - } -} - -static name_database_entry * -nss_getline (char *line) -{ - const char *name; - name_database_entry *result; - size_t len; - - /* Ignore leading white spaces. ATTENTION: this is different from - what is implemented in Solaris. The Solaris man page says a line - beginning with a white space character is ignored. We regard - this as just another misfeature in Solaris. */ - while (isspace (line[0])) - ++line; - - /* Recognize ` ":"'. */ - name = line; - while (line[0] != '\0' && !isspace (line[0]) && line[0] != ':') - ++line; - if (line[0] == '\0' || name == line) - /* Syntax error. */ - return NULL; - *line++ = '\0'; - - len = strlen (name) + 1; - - result = (name_database_entry *) malloc (sizeof (name_database_entry) + len); - if (result == NULL) - return NULL; - - /* Save the database name. */ - memcpy (result->name, name, len); - - /* Parse the list of services. */ - result->service = nss_parse_service_list (line); - - result->next = NULL; - return result; -} - - -#if !defined DO_STATIC_NSS || defined SHARED -static service_library * -nss_new_service (name_database *database, const char *name) -{ - service_library **currentp = &database->library; - - while (*currentp != NULL) - { - if (strcmp ((*currentp)->name, name) == 0) - return *currentp; - currentp = &(*currentp)->next; - } - - /* We have to add the new service. */ - *currentp = (service_library *) malloc (sizeof (service_library)); - if (*currentp == NULL) - return NULL; - - (*currentp)->name = name; - (*currentp)->lib_handle = NULL; - (*currentp)->next = NULL; - - return *currentp; -} -#endif - - -#if defined SHARED && defined USE_NSCD -/* 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_lookup2 (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 (*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", DEFAULT_CONFIG); - nss_load_all_libraries ("group", DEFAULT_CONFIG); - 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; - __nss_not_use_nscd_netgroup = -1; -} -#endif - -static void -free_database_entries (name_database_entry *entry) -{ - while (entry != NULL) - { - name_database_entry *olde = entry; - service_user *service = entry->service; - - while (service != NULL) - { - service_user *olds = service; - - if (service->known != NULL) - __tdestroy (service->known, free); - - service = service->next; - free (olds); - } - - entry = entry->next; - free (olde); - } -} - -/* Free all resources if necessary. */ -libc_freeres_fn (free_defconfig) -{ - name_database_entry *entry = defconfig_entries; - - if (entry == NULL) - /* defconfig was not used. */ - return; - - /* Don't disturb ongoing other threads (if there are any). */ - defconfig_entries = NULL; - - free_database_entries (entry); -} - -libc_freeres_fn (free_mem) -{ - name_database *top = service_table; - service_library *library; - - if (top == NULL) - /* Maybe we have not read the nsswitch.conf file. */ - return; - - /* Don't disturb ongoing other threads (if there are any). */ - service_table = NULL; - - free_database_entries (top->entry); - - library = top->library; - while (library != NULL) - { - service_library *oldl = library; - - if (library->lib_handle && library->lib_handle != (void *) -1l) - __libc_dlclose (library->lib_handle); - - library = library->next; - free (oldl); - } - - free (top); + return __nss_module_get_function (ni->module, fct_name); } +libc_hidden_def (__nss_lookup_function) diff --git a/nss/nsswitch.h b/nss/nsswitch.h index eaf81587d6..7e957d061b 100644 --- a/nss/nsswitch.h +++ b/nss/nsswitch.h @@ -36,6 +36,7 @@ typedef enum NSS_ACTION_MERGE } lookup_actions; +struct nss_action; typedef struct service_library { @@ -58,6 +59,7 @@ typedef struct } known_function; +#ifdef DJ typedef struct service_user { /* And the link to the next entry. */ @@ -71,11 +73,14 @@ typedef struct service_user /* Name of the service (`files', `dns', `nis', ...). */ char name[0]; } service_user; +#endif /* To access the action based on the status value use this macro. */ -#define nss_next_action(ni, status) ((ni)->actions[2 + status]) +#define old_nss_next_action(ni, status) ((ni)->actions[2 + status]) +#define nss_next_action(ni, status) nss_action_get (ni, status) +#ifdef DJ typedef struct name_database_entry { /* And the link to the next entry. */ @@ -94,6 +99,7 @@ typedef struct name_database /* List of libraries with service implementation. */ service_library *library; } name_database; +#endif #ifdef USE_NSCD @@ -127,13 +133,13 @@ extern bool __nss_database_custom[NSS_DBSIDX_max] attribute_hidden; than one function can use the database. */ extern int __nss_database_lookup2 (const char *database, const char *alternative_name, - const char *defconfig, service_user **ni); + const char *defconfig, struct nss_action **ni); libc_hidden_proto (__nss_database_lookup2) /* Put first function with name FCT_NAME for SERVICE in FCTP. The position is remembered in NI. The function returns a value < 0 if an error occurred or no such function exists. */ -extern int __nss_lookup (service_user **ni, const char *fct_name, +extern int __nss_lookup (struct nss_action **ni, const char *fct_name, const char *fct2_name, void **fctp); libc_hidden_proto (__nss_lookup) @@ -150,16 +156,16 @@ libc_hidden_proto (__nss_lookup) services. In other words, only if all four lookup results have the action RETURN associated the lookup process stops before the natural end. */ -extern int __nss_next2 (service_user **ni, const char *fct_name, +extern int __nss_next2 (struct nss_action **ni, const char *fct_name, const char *fct2_name, void **fctp, int status, int all_values) attribute_hidden; libc_hidden_proto (__nss_next2) -extern int __nss_next (service_user **ni, const char *fct_name, void **fctp, +extern int __nss_next (struct nss_action **ni, const char *fct_name, void **fctp, int status, int all_values); /* Search for the service described in NI for a function named FCT_NAME and return a pointer to this function if successful. */ -extern void *__nss_lookup_function (service_user *ni, const char *fct_name); +extern void *__nss_lookup_function (struct nss_action *ni, const char *fct_name); libc_hidden_proto (__nss_lookup_function) @@ -169,7 +175,7 @@ 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 *, +typedef int (*db_lookup_function) (struct nss_action **, const char *, const char *, void **); typedef enum nss_status (*setent_function) (int); typedef enum nss_status (*endent_function) (void); @@ -180,20 +186,20 @@ typedef int (*getent_r_function) (void *, char *, size_t, extern void __nss_setent (const char *func_name, db_lookup_function lookup_fct, - service_user **nip, service_user **startp, - service_user **last_nip, int stayon, + struct nss_action **nip, struct nss_action **startp, + struct nss_action **last_nip, int stayon, int *stayon_tmp, int res) attribute_hidden; extern void __nss_endent (const char *func_name, db_lookup_function lookup_fct, - service_user **nip, service_user **startp, - service_user **last_nip, int res) + struct nss_action **nip, struct nss_action **startp, + struct nss_action **last_nip, int res) attribute_hidden; extern int __nss_getent_r (const char *getent_func_name, const char *setent_func_name, db_lookup_function lookup_fct, - service_user **nip, service_user **startp, - service_user **last_nip, int *stayon_tmp, + struct nss_action **nip, struct nss_action **startp, + struct nss_action **last_nip, int *stayon_tmp, int res, void *resbuf, char *buffer, size_t buflen, void **result, int *h_errnop) @@ -227,11 +233,15 @@ libc_hidden_proto (__nss_hostname_digits_dots) /* Prototypes for __nss_*_lookup2 functions. */ #define DEFINE_DATABASE(arg) \ - extern service_user *__nss_##arg##_database attribute_hidden; \ - int __nss_##arg##_lookup2 (service_user **, const char *, \ + extern struct nss_action *__nss_##arg##_database attribute_hidden; \ + int __nss_##arg##_lookup2 (struct nss_action **, const char *, \ const char *, void **); \ libc_hidden_proto (__nss_##arg##_lookup2) #include "databases.def" #undef DEFINE_DATABASE +#include +#include +#include + #endif /* nsswitch.h */ diff --git a/posix/tst-rfc3484-2.c b/posix/tst-rfc3484-2.c index 8c64ac59ff..5f5ada9420 100644 --- a/posix/tst-rfc3484-2.c +++ b/posix/tst-rfc3484-2.c @@ -58,7 +58,7 @@ _res_hconf_init (void) #undef USE_NSCD #include "../sysdeps/posix/getaddrinfo.c" -service_user *__nss_hosts_database attribute_hidden; +nss_action_list __nss_hosts_database attribute_hidden; /* This is the beginning of the real test code. The above defines (among other things) the function rfc3484_sort. */ diff --git a/posix/tst-rfc3484-3.c b/posix/tst-rfc3484-3.c index 1c61aaf844..d9ec5cc851 100644 --- a/posix/tst-rfc3484-3.c +++ b/posix/tst-rfc3484-3.c @@ -58,7 +58,7 @@ _res_hconf_init (void) #undef USE_NSCD #include "../sysdeps/posix/getaddrinfo.c" -service_user *__nss_hosts_database attribute_hidden; +nss_action_list __nss_hosts_database attribute_hidden; /* This is the beginning of the real test code. The above defines (among other things) the function rfc3484_sort. */ diff --git a/posix/tst-rfc3484.c b/posix/tst-rfc3484.c index 8f45848e44..97d065b6bf 100644 --- a/posix/tst-rfc3484.c +++ b/posix/tst-rfc3484.c @@ -58,7 +58,7 @@ _res_hconf_init (void) #undef USE_NSCD #include "../sysdeps/posix/getaddrinfo.c" -service_user *__nss_hosts_database attribute_hidden; +nss_action_list __nss_hosts_database attribute_hidden; /* This is the beginning of the real test code. The above defines (among other things) the function rfc3484_sort. */ diff --git a/sunrpc/netname.c b/sunrpc/netname.c index 61d82ca31a..aa64362b4b 100644 --- a/sunrpc/netname.c +++ b/sunrpc/netname.c @@ -145,9 +145,7 @@ int netname2user (const char netname[MAXNETNAMELEN + 1], uid_t * uidp, gid_t * gidp, int *gidlenp, gid_t * gidlist) { - static service_user *startp; - static netname2user_function start_fct; - service_user *nip; + nss_action_list nip; union { netname2user_function f; @@ -156,22 +154,7 @@ netname2user (const char netname[MAXNETNAMELEN + 1], uid_t * uidp, gid_t * gidp, enum nss_status status = NSS_STATUS_UNAVAIL; int no_more; - if (startp == NULL) - { - no_more = __nss_publickey_lookup2 (&nip, "netname2user", NULL, &fct.ptr); - if (no_more) - startp = (service_user *) - 1; - else - { - startp = nip; - start_fct = fct.f; - } - } - else - { - fct.f = start_fct; - no_more = (nip = startp) == (service_user *) - 1; - } + no_more = __nss_publickey_lookup2 (&nip, "netname2user", NULL, &fct.ptr); while (!no_more) { diff --git a/sunrpc/publickey.c b/sunrpc/publickey.c index 2fa0252d5b..63866ef900 100644 --- a/sunrpc/publickey.c +++ b/sunrpc/publickey.c @@ -34,9 +34,7 @@ typedef int (*secret_function) (const char *, char *, const char *, int *); int getpublickey (const char *name, char *key) { - static service_user *startp; - static public_function start_fct; - service_user *nip; + nss_action_list nip; union { public_function f; @@ -45,22 +43,7 @@ getpublickey (const char *name, char *key) enum nss_status status = NSS_STATUS_UNAVAIL; int no_more; - if (startp == NULL) - { - no_more = __nss_publickey_lookup2 (&nip, "getpublickey", NULL, &fct.ptr); - if (no_more) - startp = (service_user *) -1; - else - { - startp = nip; - start_fct = fct.f; - } - } - else - { - fct.f = start_fct; - no_more = (nip = startp) == (service_user *) -1; - } + no_more = __nss_publickey_lookup2 (&nip, "getpublickey", NULL, &fct.ptr); while (! no_more) { @@ -77,9 +60,7 @@ libc_hidden_nolink_sunrpc (getpublickey, GLIBC_2_0) int getsecretkey (const char *name, char *key, const char *passwd) { - static service_user *startp; - static secret_function start_fct; - service_user *nip; + nss_action_list nip; union { secret_function f; @@ -88,22 +69,7 @@ getsecretkey (const char *name, char *key, const char *passwd) enum nss_status status = NSS_STATUS_UNAVAIL; int no_more; - if (startp == NULL) - { - no_more = __nss_publickey_lookup2 (&nip, "getsecretkey", NULL, &fct.ptr); - if (no_more) - startp = (service_user *) -1; - else - { - startp = nip; - start_fct = fct.f; - } - } - else - { - fct.f = start_fct; - no_more = (nip = startp) == (service_user *) -1; - } + no_more = __nss_publickey_lookup2 (&nip, "getsecretkey", NULL, &fct.ptr); while (! no_more) { diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c index ed04e564f9..84d3ce1957 100644 --- a/sysdeps/posix/getaddrinfo.c +++ b/sysdeps/posix/getaddrinfo.c @@ -307,7 +307,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, memory allocation failure. The returned string is allocated on the heap; the caller has to free it. */ static char * -getcanonname (service_user *nip, struct gaih_addrtuple *at, const char *name) +getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name) { nss_getcanonname_r *cfct = __nss_lookup_function (nip, "getcanonname_r"); char *s = (char *) name; @@ -538,7 +538,7 @@ gaih_inet (const char *name, const struct gaih_service *service, struct gaih_addrtuple **pat = &at; int no_data = 0; int no_inet6_data = 0; - service_user *nip; + nss_action_list nip; enum nss_status inet6_status = NSS_STATUS_UNAVAIL; enum nss_status status = NSS_STATUS_UNAVAIL; int no_more; @@ -905,10 +905,9 @@ gaih_inet (const char *name, const struct gaih_service *service, if (nss_next_action (nip, status) == NSS_ACTION_RETURN) break; - if (nip->next == NULL) + nip ++; + if (nip->module == NULL) no_more = -1; - else - nip = nip->next; } __resolv_context_put (res_ctx);