From b855cdeb01df73cdb6895c00a509570270e6adbc595400dbaad3c9e24e0797c8 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Tue, 2 Mar 2021 13:18:55 +0000 Subject: [PATCH] Accepting request 876230 from home:Andreas_Schwab:Factory - Disable x86 ISA level for now (bsc#1182522, BZ #27318) - nss-revert-api.patch: Workaround for nss-compat brokeness (bsc#1182247, BZ #27416) OBS-URL: https://build.opensuse.org/request/show/876230 OBS-URL: https://build.opensuse.org/package/show/Base:System/glibc?expand=0&rev=583 --- glibc-nsswitch-usr.diff | 26 +- glibc.changes | 7 + glibc.spec | 17 +- nss-revert-api.patch | 4609 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 4636 insertions(+), 23 deletions(-) create mode 100644 nss-revert-api.patch diff --git a/glibc-nsswitch-usr.diff b/glibc-nsswitch-usr.diff index 57c81a9..d88bf42 100644 --- a/glibc-nsswitch-usr.diff +++ b/glibc-nsswitch-usr.diff @@ -1,13 +1,15 @@ -Index: glibc-2.31/nss/nss_database.c +Index: glibc-2.33/nss/nsswitch.c =================================================================== ---- glibc-2.31.orig/nss/nss_database.c -+++ glibc-2.31/nss/nss_database.c -@@ -294,6 +294,8 @@ nss_database_reload (struct nss_database_data *staging, - struct file_change_detection *initial) - { - FILE *fp = fopen (_PATH_NSSWITCH_CONF, "rce"); -+ if (fp == NULL) -+ fp = fopen ("/usr" _PATH_NSSWITCH_CONF, "rce"); - if (fp == NULL) - switch (errno) - { +--- glibc-2.33.orig/nss/nsswitch.c ++++ glibc-2.33/nss/nsswitch.c +@@ -126,6 +126,10 @@ __nss_database_lookup2 (const char *data + /* Read config file. */ + service_table = nss_parse_file (_PATH_NSSWITCH_CONF); + ++ /* Retry with the OS vendor provided config file. */ ++ if (service_table == NULL) ++ service_table = nss_parse_file ("/usr" _PATH_NSSWITCH_CONF); ++ + /* Test whether configuration data is available. */ + if (service_table != NULL) + { diff --git a/glibc.changes b/glibc.changes index d5fa6c5..ea0fd98 100644 --- a/glibc.changes +++ b/glibc.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Tue Mar 2 11:57:15 UTC 2021 - Andreas Schwab + +- Disable x86 ISA level for now (bsc#1182522, BZ #27318) +- nss-revert-api.patch: Workaround for nss-compat brokeness (bsc#1182247, + BZ #27416) + ------------------------------------------------------------------- Mon Mar 1 16:43:55 UTC 2021 - Andreas Schwab diff --git a/glibc.spec b/glibc.spec index 7968a79..ea1fa2e 100644 --- a/glibc.spec +++ b/glibc.spec @@ -200,6 +200,8 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-build ### # Patches that upstream will not accept ### +# PATCH-FIX-OPENSUSE Work around for nss-compat brokeness +Patch1: nss-revert-api.patch ### # openSUSE specific patches - won't go upstream @@ -415,19 +417,9 @@ The glibc-devel-static package contains the C library static libraries for -static linking. You don't need these, unless you link statically, which is highly discouraged. - - - - - - - - - +%package extra # makedb requires libselinux. We add this program in a separate # package so that glibc does not require libselinux. - -%package extra Summary: Extra binaries from GNU C Library License: LGPL-2.1-or-later Group: Development/Libraries/C and C++ @@ -453,6 +445,7 @@ Internal usrmerge bootstrap helper %prep %setup -n glibc-%{version} -q -a 4 +%patch1 -p1 %patch6 -p1 %patch7 -p1 %patch8 -p1 @@ -585,6 +578,8 @@ profile="--enable-profile" %else profile="--disable-profile" %endif +# Disable x86 ISA level support for now (bsc#1182522) +export libc_cv_include_x86_isa_level=no ../configure \ CFLAGS="$conf_cflags" BUILD_CFLAGS="$conf_cflags" \ CC="$BuildCC" CXX="$BuildCCplus" \ diff --git a/nss-revert-api.patch b/nss-revert-api.patch new file mode 100644 index 0000000..eb9a8f9 --- /dev/null +++ b/nss-revert-api.patch @@ -0,0 +1,4609 @@ +Index: glibc-2.33/grp/Makefile +=================================================================== +--- glibc-2.33.orig/grp/Makefile ++++ glibc-2.33/grp/Makefile +@@ -31,10 +31,6 @@ routines := fgetgrent initgroups setgrou + + tests := testgrp tst-putgrent + +-tests-container = \ +- tst-initgroups1 \ +- tst-initgroups2 +- + ifeq (yes,$(build-shared)) + test-srcs := tst_fgetgrent + ifeq ($(run-built-tests),yes) +Index: glibc-2.33/grp/compat-initgroups.c +=================================================================== +--- glibc-2.33.orig/grp/compat-initgroups.c ++++ glibc-2.33/grp/compat-initgroups.c +@@ -10,7 +10,7 @@ typedef enum nss_status (*get_function) + + + static enum nss_status +-compat_call (nss_action_list nip, const char *user, gid_t group, long int *start, ++compat_call (service_user *nip, const char *user, gid_t group, long int *start, + long int *size, gid_t **groupsp, long int limit, int *errnop) + { + struct group grpbuf; +Index: glibc-2.33/grp/initgroups.c +=================================================================== +--- glibc-2.33.orig/grp/initgroups.c ++++ glibc-2.33/grp/initgroups.c +@@ -63,6 +63,7 @@ internal_getgrouplist (const char *user, + #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); +@@ -70,25 +71,28 @@ internal_getgrouplist (const char *user, + /* Start is one, because we have the first group as parameter. */ + long int start = 1; + +- nss_action_list nip; +- +- if (__nss_database_get (nss_database_initgroups, &nip) +- && nip != NULL) +- { +- use_initgroups_entry = true; +- } +- else if (__nss_database_get (nss_database_group, &nip) +- && nip != NULL) ++ if (__nss_initgroups_database == NULL) + { +- use_initgroups_entry = false; ++ if (__nss_database_lookup2 ("initgroups", NULL, "", ++ &__nss_initgroups_database) < 0) ++ { ++ if (__nss_group_database == NULL) ++ no_more = __nss_database_lookup2 ("group", NULL, "files", ++ &__nss_group_database); ++ ++ __nss_initgroups_database = __nss_group_database; ++ } ++ else ++ use_initgroups_entry = true; + } + else +- { +- nip = __nss_action_parse ("files"); +- use_initgroups_entry = false; +- } ++ /* __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; + +- while (nip && nip->module) ++ service_user *nip = __nss_initgroups_database; ++ while (! no_more) + { + long int prev_start = start; + +@@ -130,7 +134,10 @@ internal_getgrouplist (const char *user, + && nss_next_action (nip, status) == NSS_ACTION_RETURN) + break; + +- nip++; ++ if (nip->next == NULL) ++ no_more = -1; ++ else ++ nip = nip->next; + } + + return start; +Index: glibc-2.33/grp/tst-initgroups1.c +=================================================================== +--- glibc-2.33.orig/grp/tst-initgroups1.c ++++ /dev/null +@@ -1,56 +0,0 @@ +-/* Test that initgroups works. +- Copyright (C) 2020-2021 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 +- +-/* Test that initgroups includes secondary groups. +- https://bugzilla.redhat.com/show_bug.cgi?id=1906066 */ +- +-/* This version uses the wrapper around the groups module. */ +- +-#define EXPECTED_N_GROUPS 4 +-static gid_t expected_groups[] = +- { 20, 30, 50, 51 }; +- +-static int +-do_test (void) +-{ +- gid_t mygroups [50]; +- int i, n; +- +- n = 50; +- getgrouplist ("dj", 20, mygroups, &n); +- +- TEST_COMPARE (n, EXPECTED_N_GROUPS); +- for (i=0; i +Index: glibc-2.33/grp/tst-initgroups1.root/etc/group +=================================================================== +--- glibc-2.33.orig/grp/tst-initgroups1.root/etc/group ++++ /dev/null +@@ -1,7 +0,0 @@ +-abc:x:10: +-def:x:20: +-ghi:x:30:dj +-jkl:x:40: +-m:x:50:not,dj +-n:x:51:dj,not +-np:x:60:djx +Index: glibc-2.33/grp/tst-initgroups1.root/etc/nsswitch.conf +=================================================================== +--- glibc-2.33.orig/grp/tst-initgroups1.root/etc/nsswitch.conf ++++ /dev/null +@@ -1 +0,0 @@ +-group : files +Index: glibc-2.33/grp/tst-initgroups1.root/etc/passwd +=================================================================== +--- glibc-2.33.orig/grp/tst-initgroups1.root/etc/passwd ++++ /dev/null +@@ -1 +0,0 @@ +-dj:x:84:20:DJ:/:/bin/sh +Index: glibc-2.33/grp/tst-initgroups2.c +=================================================================== +--- glibc-2.33.orig/grp/tst-initgroups2.c ++++ /dev/null +@@ -1,21 +0,0 @@ +-/* Test that initgroups works. +- Copyright (C) 2020-2021 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 "tst-initgroups1.c" +- +-/* This version uses the initgroups built in to the files module. */ +Index: glibc-2.33/grp/tst-initgroups2.root/etc/group +=================================================================== +--- glibc-2.33.orig/grp/tst-initgroups2.root/etc/group ++++ /dev/null +@@ -1,7 +0,0 @@ +-abc:x:10: +-def:x:20: +-ghi:x:30:dj +-jkl:x:40: +-m:x:50:not,dj +-n:x:51:dj,not +-np:x:60:djx +Index: glibc-2.33/grp/tst-initgroups2.root/etc/nsswitch.conf +=================================================================== +--- glibc-2.33.orig/grp/tst-initgroups2.root/etc/nsswitch.conf ++++ /dev/null +@@ -1,2 +0,0 @@ +-initgroups : files +-group : notfiles +Index: glibc-2.33/grp/tst-initgroups2.root/etc/passwd +=================================================================== +--- glibc-2.33.orig/grp/tst-initgroups2.root/etc/passwd ++++ /dev/null +@@ -1 +0,0 @@ +-dj:x:84:20:DJ:/:/bin/sh +Index: glibc-2.33/inet/ether_hton.c +=================================================================== +--- glibc-2.33.orig/inet/ether_hton.c ++++ glibc-2.33/inet/ether_hton.c +@@ -30,7 +30,9 @@ typedef int (*lookup_function) (const ch + int + ether_hostton (const char *hostname, struct ether_addr *addr) + { +- nss_action_list nip; ++ static service_user *startp; ++ static lookup_function start_fct; ++ service_user *nip; + union + { + lookup_function f; +@@ -40,7 +42,22 @@ ether_hostton (const char *hostname, str + enum nss_status status = NSS_STATUS_UNAVAIL; + struct etherent etherent; + +- no_more = __nss_ethers_lookup2 (&nip, "gethostton_r", NULL, &fct.ptr); ++ 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; ++ } + + while (no_more == 0) + { +Index: glibc-2.33/inet/ether_ntoh.c +=================================================================== +--- glibc-2.33.orig/inet/ether_ntoh.c ++++ glibc-2.33/inet/ether_ntoh.c +@@ -31,7 +31,9 @@ typedef int (*lookup_function) (const st + int + ether_ntohost (char *hostname, const struct ether_addr *addr) + { +- nss_action_list nip; ++ static service_user *startp; ++ static lookup_function start_fct; ++ service_user *nip; + union + { + lookup_function f; +@@ -41,7 +43,22 @@ ether_ntohost (char *hostname, const str + enum nss_status status = NSS_STATUS_UNAVAIL; + struct etherent etherent; + +- no_more = __nss_ethers_lookup2 (&nip, "getntohost_r", NULL, &fct.ptr); ++ 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; ++ } + + while (no_more == 0) + { +Index: glibc-2.33/inet/getnetgrent_r.c +=================================================================== +--- glibc-2.33.orig/inet/getnetgrent_r.c ++++ glibc-2.33/inet/getnetgrent_r.c +@@ -39,12 +39,40 @@ 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, nss_action_list *nipp) ++setup (void **fctp, service_user **nipp) + { ++ /* Remember the first service_entry, it's always the same. */ ++ static bool startp_initialized; ++ static service_user *startp; + int no_more; + +- no_more = __nss_netgroup_lookup2 (nipp, "setnetgrent", NULL, fctp); +- ++ 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); ++ } + return no_more; + } + +@@ -72,7 +100,7 @@ endnetgrent_hook (struct __netgrent *dat + { + enum nss_status (*endfct) (struct __netgrent *); + +- if (datap->nip == NULL || datap->nip == (nss_action_list) -1l) ++ if (datap->nip == NULL || datap->nip == (service_user *) -1l) + return; + + endfct = __nss_lookup_function (datap->nip, "endnetgrent"); +@@ -105,7 +133,7 @@ __internal_setnetgrent_reuse (const char + /* Ignore status, we force check in `__nss_next2'. */ + status = DL_CALL_FCT (*fct.f, (group, datap)); + +- nss_action_list old_nip = datap->nip; ++ service_user *old_nip = datap->nip; + no_more = __nss_next2 (&datap->nip, "setnetgrent", NULL, &fct.ptr, + status, 0); + +@@ -247,7 +275,7 @@ __internal_getnetgrent_r (char **hostp, + /* 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 == (nss_action_list) -1l) ++ if (datap->nip == (service_user *) -1l) + fct = nscd_getnetgrent; + else + #endif +Index: glibc-2.33/inet/netgroup.h +=================================================================== +--- glibc-2.33.orig/inet/netgroup.h ++++ glibc-2.33/inet/netgroup.h +@@ -64,7 +64,7 @@ struct __netgrent + + /* This handle for the NSS data base is shared between all + set/get/endXXXent functions. */ +- struct nss_action *nip; ++ service_user *nip; + }; + + +Index: glibc-2.33/malloc/set-freeres.c +=================================================================== +--- glibc-2.33.orig/malloc/set-freeres.c ++++ glibc-2.33/malloc/set-freeres.c +@@ -20,7 +20,6 @@ + #include + #include + +-#include "../nss/nsswitch.h" + #include "../libio/libioP.h" + + DEFINE_HOOK (__libc_subfreeres, (void)); +@@ -42,10 +41,6 @@ __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 (); + + /* We run the resource freeing after IO cleanup. */ +Index: glibc-2.33/nscd/aicache.c +=================================================================== +--- glibc-2.33.orig/nscd/aicache.c ++++ glibc-2.33/nscd/aicache.c +@@ -71,15 +71,20 @@ addhstaiX (struct database_dyn *db, int + dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) key); + } + +- nss_action_list nip; ++ static service_user *hosts_database; ++ service_user *nip; + int no_more; + int rc6 = 0; + int rc4 = 0; + int herrno = 0; + +- no_more = __nss_database_lookup2 ("hosts", NULL, +- "dns [!UNAVAIL=return] files", +- &nip); ++ if (hosts_database == NULL) ++ no_more = __nss_database_lookup2 ("hosts", NULL, ++ "dns [!UNAVAIL=return] files", ++ &hosts_database); ++ else ++ no_more = 0; ++ nip = hosts_database; + + /* Initialize configurations. */ + struct resolv_context *ctx = __resolv_context_get (); +@@ -437,10 +442,10 @@ next_nip: + if (nss_next_action (nip, status[1]) == NSS_ACTION_RETURN) + break; + +- if (nip[1].module == NULL) ++ if (nip->next == NULL) + no_more = -1; + else +- ++nip; ++ nip = nip->next; + } + + /* No result found. Create a negative result record. */ +Index: glibc-2.33/nscd/gai.c +=================================================================== +--- glibc-2.33.orig/nscd/gai.c ++++ glibc-2.33/nscd/gai.c +@@ -48,4 +48,4 @@ + #include + + /* Some variables normally defined in libc. */ +-nss_action_list __nss_hosts_database attribute_hidden; ++service_user *__nss_hosts_database attribute_hidden; +Index: glibc-2.33/nscd/initgrcache.c +=================================================================== +--- glibc-2.33.orig/nscd/initgrcache.c ++++ glibc-2.33/nscd/initgrcache.c +@@ -77,8 +77,8 @@ addinitgroupsX (struct database_dyn *db, + dbg_log (_("Reloading \"%s\" in group cache!"), (char *) key); + } + +- static nss_action_list group_database; +- nss_action_list nip; ++ static service_user *group_database; ++ service_user *nip; + int no_more; + + if (group_database == NULL) +@@ -161,10 +161,10 @@ addinitgroupsX (struct database_dyn *db, + && nss_next_action (nip, status) == NSS_ACTION_RETURN) + break; + +- if (nip[1].module == NULL) ++ if (nip->next == NULL) + no_more = -1; + else +- ++nip; ++ nip = nip->next; + } + + bool all_written; +Index: glibc-2.33/nscd/netgroupcache.c +=================================================================== +--- glibc-2.33.orig/nscd/netgroupcache.c ++++ glibc-2.33/nscd/netgroupcache.c +@@ -124,7 +124,7 @@ addgetnetgrentX (struct database_dyn *db + dbg_log (_("Reloading \"%s\" in netgroup cache!"), key); + } + +- static nss_action_list netgroup_database; ++ static service_user *netgroup_database; + time_t timeout; + struct dataset *dataset; + bool cacheable = false; +@@ -175,7 +175,7 @@ addgetnetgrentX (struct database_dyn *db + void *ptr; + } setfct; + +- nss_action_list nip = netgroup_database; ++ service_user *nip = netgroup_database; + int no_more = __nss_lookup (&nip, "setnetgrent", NULL, &setfct.ptr); + while (!no_more) + { +Index: glibc-2.33/nscd/nscd_netgroup.c +=================================================================== +--- glibc-2.33.orig/nscd/nscd_netgroup.c ++++ glibc-2.33/nscd/nscd_netgroup.c +@@ -116,7 +116,7 @@ __nscd_setnetgrent (const char *group, s + datap->data_size = datalen; + datap->cursor = respdata; + datap->first = 1; +- datap->nip = (nss_action_list) -1l; ++ datap->nip = (service_user *) -1l; + datap->known_groups = NULL; + datap->needed_groups = NULL; + +Index: glibc-2.33/nss/Makefile +=================================================================== +--- glibc-2.33.orig/nss/Makefile ++++ glibc-2.33/nss/Makefile +@@ -30,8 +30,7 @@ routines = nsswitch getnssent getnssent + $(addsuffix -lookup,$(databases)) \ + compat-lookup nss_hash nss_files_fopen \ + nss_readline nss_parse_line_result \ +- nss_fgetent_r nss_module nss_action \ +- nss_action_parse nss_database ++ nss_fgetent_r + + # These are the databases that go through nss dispatch. + # Caution: if you add a database here, you must add its real name +@@ -66,8 +65,7 @@ tests-container = \ + tst-nss-test3 \ + tst-nss-files-hosts-long \ + tst-nss-db-endpwent \ +- tst-nss-db-endgrent \ +- tst-reload1 tst-reload2 ++ tst-nss-db-endgrent + + # Tests which need libdl + ifeq (yes,$(build-shared)) +Index: glibc-2.33/nss/XXX-lookup.c +=================================================================== +--- glibc-2.33.orig/nss/XXX-lookup.c ++++ glibc-2.33/nss/XXX-lookup.c +@@ -53,11 +53,12 @@ + #endif + + int +-DB_LOOKUP_FCT (nss_action_list *ni, const char *fct_name, const char *fct2_name, ++DB_LOOKUP_FCT (service_user **ni, const char *fct_name, const char *fct2_name, + void **fctp) + { +- if (__nss_database_lookup2 (DATABASE_NAME_STRING, ALTERNATE_NAME_STRING, +- DEFAULT_CONFIG, &DATABASE_NAME_SYMBOL) < 0) ++ if (DATABASE_NAME_SYMBOL == NULL ++ && __nss_database_lookup2 (DATABASE_NAME_STRING, ALTERNATE_NAME_STRING, ++ DEFAULT_CONFIG, &DATABASE_NAME_SYMBOL) < 0) + return -1; + + *ni = DATABASE_NAME_SYMBOL; +Index: glibc-2.33/nss/compat-lookup.c +=================================================================== +--- glibc-2.33.orig/nss/compat-lookup.c ++++ glibc-2.33/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 (nss_action_list *ni, const char *fct_name, void **fctp) ++__nss_passwd_lookup (service_user **ni, const char *fct_name, void **fctp) + { + __set_errno (ENOSYS); + return -1; +@@ -46,11 +46,11 @@ compat_symbol (libc, __nss_hosts_lookup, + + /* These functions were exported under a non-GLIBC_PRIVATE version, + even though it is not usable externally due to the service_user +- (now nss_action_list) type dependency. */ ++ type dependency. */ + + int + attribute_compat_text_section +-__nss_next (nss_action_list *ni, const char *fct_name, void **fctp, int status, ++__nss_next (service_user **ni, const char *fct_name, void **fctp, int status, + int all_values) + { + return -1; +@@ -60,7 +60,7 @@ compat_symbol (libc, __nss_next, __nss_n + int + attribute_compat_text_section + __nss_database_lookup (const char *database, const char *alternate_name, +- const char *defconfig, nss_action_list *ni) ++ const char *defconfig, service_user **ni) + { + *ni = NULL; + return -1; +Index: glibc-2.33/nss/function.def +=================================================================== +--- glibc-2.33.orig/nss/function.def ++++ glibc-2.33/nss/function.def +@@ -1,5 +1,5 @@ +-/* List of all functions defined for the NSS in GNU C Library. +- Copyright (C) 1996-2021 Free Software Foundation, Inc. ++/* List of functions defined for static NSS in GNU C Library. ++ 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 +@@ -16,69 +16,63 @@ + License along with the GNU C Library; if not, see + . */ + +-/* This list must be kept sorted!!! */ ++/* ++ This is a minimal config. Only services `files' and `dns' are supported. ++*/ + +-DEFINE_NSS_FUNCTION (endaliasent) +-DEFINE_NSS_FUNCTION (endetherent) +-DEFINE_NSS_FUNCTION (endgrent) +-DEFINE_NSS_FUNCTION (endhostent) +-DEFINE_NSS_FUNCTION (endnetent) +-DEFINE_NSS_FUNCTION (endnetgrent) +-DEFINE_NSS_FUNCTION (endprotoent) +-DEFINE_NSS_FUNCTION (endpwent) +-DEFINE_NSS_FUNCTION (endrpcent) +-DEFINE_NSS_FUNCTION (endservent) +-DEFINE_NSS_FUNCTION (endsgent) +-DEFINE_NSS_FUNCTION (endspent) +-DEFINE_NSS_FUNCTION (getaliasbyname_r) +-DEFINE_NSS_FUNCTION (getaliasent_r) +-DEFINE_NSS_FUNCTION (getcanonname_r) +-DEFINE_NSS_FUNCTION (getetherent_r) +-DEFINE_NSS_FUNCTION (getgrent_r) +-DEFINE_NSS_FUNCTION (getgrgid_r) +-DEFINE_NSS_FUNCTION (getgrnam_r) +-DEFINE_NSS_FUNCTION (gethostbyaddr2_r) +-DEFINE_NSS_FUNCTION (gethostbyaddr_r) +-DEFINE_NSS_FUNCTION (gethostbyname2_r) +-DEFINE_NSS_FUNCTION (gethostbyname3_r) +-DEFINE_NSS_FUNCTION (gethostbyname4_r) +-DEFINE_NSS_FUNCTION (gethostbyname_r) +-DEFINE_NSS_FUNCTION (gethostent_r) +-DEFINE_NSS_FUNCTION (gethostton_r) +-DEFINE_NSS_FUNCTION (getnetbyaddr_r) +-DEFINE_NSS_FUNCTION (getnetbyname_r) +-DEFINE_NSS_FUNCTION (getnetent_r) +-DEFINE_NSS_FUNCTION (getnetgrent_r) +-DEFINE_NSS_FUNCTION (getntohost_r) +-DEFINE_NSS_FUNCTION (getprotobyname_r) +-DEFINE_NSS_FUNCTION (getprotobynumber_r) +-DEFINE_NSS_FUNCTION (getprotoent_r) +-DEFINE_NSS_FUNCTION (getpublickey) +-DEFINE_NSS_FUNCTION (getpwent_r) +-DEFINE_NSS_FUNCTION (getpwnam_r) +-DEFINE_NSS_FUNCTION (getpwuid_r) +-DEFINE_NSS_FUNCTION (getrpcbyname_r) +-DEFINE_NSS_FUNCTION (getrpcbynumber_r) +-DEFINE_NSS_FUNCTION (getrpcent_r) +-DEFINE_NSS_FUNCTION (getsecretkey) +-DEFINE_NSS_FUNCTION (getservbyname_r) +-DEFINE_NSS_FUNCTION (getservbyport_r) +-DEFINE_NSS_FUNCTION (getservent_r) +-DEFINE_NSS_FUNCTION (getsgent_r) +-DEFINE_NSS_FUNCTION (getsgnam_r) +-DEFINE_NSS_FUNCTION (getspent_r) +-DEFINE_NSS_FUNCTION (getspnam_r) +-DEFINE_NSS_FUNCTION (initgroups_dyn) +-DEFINE_NSS_FUNCTION (netname2user) +-DEFINE_NSS_FUNCTION (setaliasent) +-DEFINE_NSS_FUNCTION (setetherent) +-DEFINE_NSS_FUNCTION (setgrent) +-DEFINE_NSS_FUNCTION (sethostent) +-DEFINE_NSS_FUNCTION (setnetent) +-DEFINE_NSS_FUNCTION (setnetgrent) +-DEFINE_NSS_FUNCTION (setprotoent) +-DEFINE_NSS_FUNCTION (setpwent) +-DEFINE_NSS_FUNCTION (setrpcent) +-DEFINE_NSS_FUNCTION (setservent) +-DEFINE_NSS_FUNCTION (setsgent) +-DEFINE_NSS_FUNCTION (setspent) ++/* aliases */ ++DEFINE_ENT (files, alias) ++DEFINE_GETBY (files, alias, name) ++ ++/* ethers */ ++DEFINE_ENT (files, ether) ++ ++/* group */ ++DEFINE_ENT (files, gr) ++DEFINE_GET (files, grgid) ++DEFINE_GET (files, grnam) ++ ++/* hosts */ ++DEFINE_ENT (files, host) ++DEFINE_GETBY (files, host, addr) ++DEFINE_GETBY (files, host, name) ++DEFINE_GETBY (files, host, name2) ++DEFINE_GET (files, hostton) ++DEFINE_GET (files, ntohost) ++DEFINE_GETBY (dns, host, addr) ++DEFINE_GETBY (dns, host, name) ++DEFINE_GETBY (dns, host, name2) ++ ++/* netgroup */ ++DEFINE_ENT (files, netgr) ++ ++/* networks */ ++DEFINE_ENT (files, net) ++DEFINE_GETBY (files, net, name) ++DEFINE_GETBY (files, net, addr) ++DEFINE_GETBY (dns, net, name) ++DEFINE_GETBY (dns, net, addr) ++ ++/* protocols */ ++DEFINE_ENT (files, proto) ++DEFINE_GETBY (files, proto, name) ++DEFINE_GETBY (files, proto, number) ++ ++/* passwd */ ++DEFINE_ENT (files, pw) ++DEFINE_GET (files, pwnam) ++DEFINE_GET (files, pwuid) ++ ++/* rpc */ ++DEFINE_ENT (files, rpc) ++DEFINE_GETBY (files, rpc, name) ++DEFINE_GETBY (files, rpc, number) ++ ++/* services */ ++DEFINE_ENT (files, serv) ++DEFINE_GETBY (files, serv, name) ++DEFINE_GETBY (files, serv, port) ++ ++/* shadow */ ++DEFINE_ENT (files, sp) ++DEFINE_GET (files, spnam) +Index: glibc-2.33/nss/getXXbyYY_r.c +=================================================================== +--- glibc-2.33.orig/nss/getXXbyYY_r.c ++++ glibc-2.33/nss/getXXbyYY_r.c +@@ -179,7 +179,7 @@ typedef enum nss_status (*lookup_functio + EXTRA_PARAMS); + + /* The lookup function for the first entry of this service. */ +-extern int DB_LOOKUP_FCT (nss_action_list *nip, const char *name, ++extern int DB_LOOKUP_FCT (service_user **nip, const char *name, + const char *name2, void **fctp); + libc_hidden_proto (DB_LOOKUP_FCT) + +@@ -189,7 +189,10 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, L + size_t buflen, LOOKUP_TYPE **result H_ERRNO_PARM + EXTRA_PARAMS) + { +- nss_action_list nip; ++ static bool startp_initialized; ++ static service_user *startp; ++ static lookup_function start_fct; ++ service_user *nip; + int do_merge = 0; + LOOKUP_TYPE mergegrp; + char *mergebuf = NULL; +@@ -224,7 +227,6 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, L + PREPROCESS; + #endif + +- + #ifdef HANDLE_DIGITS_DOTS + switch (__nss_hostname_digits_dots (name, resbuf, &buffer, NULL, + buflen, result, &status, AF_VAL, +@@ -262,8 +264,47 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, L + } + #endif + +- no_more = DB_LOOKUP_FCT (&nip, REENTRANT_NAME_STRING, +- REENTRANT2_NAME_STRING, &fct.ptr); ++ if (! startp_initialized) ++ { ++ no_more = DB_LOOKUP_FCT (&nip, REENTRANT_NAME_STRING, ++ REENTRANT2_NAME_STRING, &fct.ptr); ++ if (no_more) ++ { ++ void *tmp_ptr = (service_user *) -1l; ++#ifdef PTR_MANGLE ++ PTR_MANGLE (tmp_ptr); ++#endif ++ startp = tmp_ptr; ++ } ++ else ++ { ++ void *tmp_ptr = fct.l; ++#ifdef PTR_MANGLE ++ PTR_MANGLE (tmp_ptr); ++#endif ++ start_fct = tmp_ptr; ++ tmp_ptr = nip; ++#ifdef PTR_MANGLE ++ PTR_MANGLE (tmp_ptr); ++#endif ++ startp = tmp_ptr; ++ } ++ ++ /* Make sure start_fct and startp are written before ++ startp_initialized. */ ++ atomic_write_barrier (); ++ startp_initialized = true; ++ } ++ else ++ { ++ fct.l = start_fct; ++ nip = startp; ++#ifdef PTR_DEMANGLE ++ PTR_DEMANGLE (fct.l); ++ PTR_DEMANGLE (nip); ++#endif ++ no_more = nip == (service_user *) -1l; ++ } + + while (no_more == 0) + { +Index: glibc-2.33/nss/getXXent_r.c +=================================================================== +--- glibc-2.33.orig/nss/getXXent_r.c ++++ glibc-2.33/nss/getXXent_r.c +@@ -95,11 +95,11 @@ + + /* This handle for the NSS data base is shared between all + set/get/endXXXent functions. */ +-static nss_action_list nip; ++static service_user *nip; + /* Remember the last service used since the last call to `endXXent'. */ +-static nss_action_list last_nip; +-/* Remember the first service_entry across set/get/endent. */ +-static nss_action_list startp; ++static service_user *last_nip; ++/* Remember the first service_entry, it's always the same. */ ++static service_user *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 (nss_action_list *nip, const char *name, ++extern int DB_LOOKUP_FCT (service_user **nip, const char *name, + const char *name2, void **fctp); + libc_hidden_proto (DB_LOOKUP_FCT) + +Index: glibc-2.33/nss/getnssent_r.c +=================================================================== +--- glibc-2.33.orig/nss/getnssent_r.c ++++ glibc-2.33/nss/getnssent_r.c +@@ -25,20 +25,20 @@ + services (left). */ + static int + setup (const char *func_name, db_lookup_function lookup_fct, +- void **fctp, nss_action_list *nip, nss_action_list *startp, int all) ++ void **fctp, service_user **nip, service_user **startp, int all) + { + int no_more; +- if (*startp == NULL || all) ++ if (*startp == NULL) + { + no_more = lookup_fct (nip, func_name, NULL, fctp); +- *startp = no_more ? (nss_action_list) -1l : *nip; ++ *startp = no_more ? (service_user *) -1l : *nip; + } +- else if (*startp == (nss_action_list) -1l) ++ else if (*startp == (service_user *) -1l) + /* No services at all. */ + return 1; + else + { +- if (!*nip) ++ if (all || !*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_ + + void + __nss_setent (const char *func_name, db_lookup_function lookup_fct, +- nss_action_list *nip, nss_action_list *startp, +- nss_action_list *last_nip, int stayopen, int *stayopen_tmp, ++ service_user **nip, service_user **startp, ++ service_user **last_nip, int stayopen, int *stayopen_tmp, + int res) + { + union +@@ -110,8 +110,8 @@ __nss_setent (const char *func_name, db_ + + void + __nss_endent (const char *func_name, db_lookup_function lookup_fct, +- nss_action_list *nip, nss_action_list *startp, +- nss_action_list *last_nip, int res) ++ service_user **nip, service_user **startp, ++ service_user **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, +- nss_action_list *nip, nss_action_list *startp, +- nss_action_list *last_nip, int *stayopen_tmp, int res, ++ service_user **nip, service_user **startp, ++ service_user **last_nip, int *stayopen_tmp, int res, + void *resbuf, char *buffer, size_t buflen, + void **result, int *h_errnop) + { +Index: glibc-2.33/nss/nss_action.c +=================================================================== +--- glibc-2.33.orig/nss/nss_action.c ++++ /dev/null +@@ -1,116 +0,0 @@ +-/* NSS actions, elements in a nsswitch.conf configuration line. +- Copyright (c) 2020-2021 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. */ +- 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[]; +-}; +- +-/* Toplevel list of allocated NSS action lists. */ +-static struct nss_action_list_wrapper *nss_actions; +- +-/* Lock covers the nss_actions list. */ +-__libc_lock_define (static, nss_actions_lock); +- +-/* Returns true if the actions are equal (same module, same actions +- array). */ +-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 COUNT actions at A and B are equal (according to +- actions_equal above). Caller must ensure that either A or B have at +- least COUNT actions. */ +-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; +-} +Index: glibc-2.33/nss/nss_action.h +=================================================================== +--- glibc-2.33.orig/nss/nss_action.h ++++ /dev/null +@@ -1,108 +0,0 @@ +-/* NSS actions, elements in a nsswitch.conf configuration line. +- Copyright (c) 2020-2021 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 +- +-/* See nss_database.h for a summary of how this relates. */ +- +-#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; +-}; +- +-/* Value to add to first nss_status value to get zero. */ +-#define NSS_STATUS_BIAS 2 +-/* Number of bits per lookup action. */ +-#define NSS_BPL 2 +-#define NSS_BPL_MASK ((1 << NSS_BPL) - 1) +- +-/* Index in actions of an NSS status. Note that in nss/nss.h the +- status starts at -2, and we shift that up to zero by adding 2. +- Thus for example NSS_STATUS_TRYAGAIN, which is -2, would index into +- the 0th bit place as expected. */ +-static inline int +-nss_actions_bits_index (enum nss_status status) +-{ +- return NSS_BPL * (NSS_STATUS_BIAS + 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)) +- & NSS_BPL_MASK); +-} +- +-/* 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 = NSS_BPL_MASK << 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 & NSS_BPL_MASK; +- action->action_bits = ( bits +- | (bits << (NSS_BPL * 1)) +- | (bits << (NSS_BPL * 2)) +- | (bits << (NSS_BPL * 3)) +- | (bits << (NSS_BPL * 4)) +- ); +-} +- +-/* 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 */ +Index: glibc-2.33/nss/nss_action_parse.c +=================================================================== +--- glibc-2.33.orig/nss/nss_action_parse.c ++++ /dev/null +@@ -1,191 +0,0 @@ +-/* Parse a service line from nsswitch.conf. +- Copyright (c) 1996-2021 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 +- +-/* Staging area during parsing. */ +-#define DYNARRAY_STRUCT action_list +-#define DYNARRAY_ELEMENT struct nss_action +-#define DYNARRAY_PREFIX action_list_ +-#include +- +-/* Skip whitespace in line[]. */ +-#define SKIP_WS() \ +- while (line[0] != '\0' && isspace (line[0])) \ +- ++line; +- +-/* Read the source names: +- `( ( "[" "!"? ( "=" )+ "]" )? )*' +- */ +-static bool +-nss_action_parse (const char *line, struct action_list *result) +-{ +- while (1) +- { +- SKIP_WS (); +- if (line[0] == '\0') +- /* No more sources specified. */ +- return true; +- +- /* 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); +- +- SKIP_WS (); +- +- if (line[0] == '[') +- { +- /* Read criterions. */ +- +- /* Skip the '['. */ +- ++line; +- SKIP_WS (); +- +- do +- { +- int not; +- enum nss_status status; +- lookup_actions action; +- +- /* Grok ! before name to mean all statuses 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 statuses. */ +- 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; +- +- SKIP_WS (); +- if (line[0] != '=') +- return false; +- +- /* Skip the '='. */ +- ++line; +- SKIP_WS (); +- 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_WS (); +- } +- 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; +- 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)) +- { +- /* Memory allocation error. */ +- __set_errno (ENOMEM); +- return NULL; +- } +- else +- { +- /* Parse error. */ +- __set_errno (EINVAL); +- return NULL; +- } +-} +Index: glibc-2.33/nss/nss_compat/compat-grp.c +=================================================================== +--- glibc-2.33.orig/nss/nss_compat/compat-grp.c ++++ glibc-2.33/nss/nss_compat/compat-grp.c +@@ -30,7 +30,7 @@ + + NSS_DECLARE_MODULE_FUNCTIONS (compat) + +-static nss_action_list ni; ++static service_user *ni; + static enum nss_status (*setgrent_impl) (int stayopen); + static enum nss_status (*getgrnam_r_impl) (const char *name, + struct group * grp, char *buffer, +Index: glibc-2.33/nss/nss_compat/compat-initgroups.c +=================================================================== +--- glibc-2.33.orig/nss/nss_compat/compat-initgroups.c ++++ glibc-2.33/nss/nss_compat/compat-initgroups.c +@@ -33,7 +33,7 @@ + + NSS_DECLARE_MODULE_FUNCTIONS (compat) + +-static nss_action_list ni; ++static service_user *ni; + static enum nss_status (*initgroups_dyn_impl) (const char *, gid_t, + long int *, long int *, + gid_t **, long int, int *); +Index: glibc-2.33/nss/nss_compat/compat-pwd.c +=================================================================== +--- glibc-2.33.orig/nss/nss_compat/compat-pwd.c ++++ glibc-2.33/nss/nss_compat/compat-pwd.c +@@ -34,7 +34,7 @@ + + NSS_DECLARE_MODULE_FUNCTIONS (compat) + +-static nss_action_list ni; ++static service_user *ni; + static enum nss_status (*setpwent_impl) (int stayopen); + static enum nss_status (*getpwnam_r_impl) (const char *name, + struct passwd * pwd, char *buffer, +Index: glibc-2.33/nss/nss_compat/compat-spwd.c +=================================================================== +--- glibc-2.33.orig/nss/nss_compat/compat-spwd.c ++++ glibc-2.33/nss/nss_compat/compat-spwd.c +@@ -34,7 +34,7 @@ + + NSS_DECLARE_MODULE_FUNCTIONS (compat) + +-static nss_action_list ni; ++static service_user *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, +Index: glibc-2.33/nss/nss_database.c +=================================================================== +--- glibc-2.33.orig/nss/nss_database.c ++++ /dev/null +@@ -1,497 +0,0 @@ +-/* Mapping NSS services to action lists. +- Copyright (C) 2020-2021 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); +- /* If "/" changes, we switched into a container and do NOT want to +- reload anything. This data must be persistent across +- reloads. */ +- ino64_t root_ino; +- dev_t root_dev; +-}; +- +- +-/* Global NSS database state. Underlying type is "struct +- nss_database_state *" but the allocate_once API requires +- "void *". */ +-static void *global_database_state; +- +-/* Allocate and return pointer to nss_database_state object or +- on failure return NULL. */ +-static void * +-global_state_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); +- result->root_ino = 0; +- result->root_dev = 0; +- } +- return result; +-} +- +-/* Return pointer to global NSS database state, allocating as +- required, or returning NULL on failure. */ +-static struct nss_database_state * +-nss_database_state_get (void) +-{ +- return allocate_once (&global_database_state, global_state_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; +- while (line[0] != '\0' && (isspace (line[0]) || line[0] == ':')) +- *line++ = '\0'; +- +- int db = name_to_database_index (name); +- if (db < 0) +- /* Not our database e.g. sudoers, automount, etc. */ +- return true; +- +- nss_action_list result = __nss_action_parse (line); +- if (result == NULL) +- return false; +- data->services[db] = result; +- 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 +-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) +-{ +- struct stat64 str; +- +- /* 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)) +- { +- *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)) +- 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; +- } +- +- /* Before we reload, verify that "/" hasn't changed. We assume that +- errors here are very unlikely, but the chance that we're entering +- a container is also very unlikely, so we err on the side of both +- very unlikely things not happening at the same time. */ +- if (__stat64 ("/", &str) != 0 +- || (local->root_ino != 0 +- && (str.st_ino != local->root_ino +- || str.st_dev != local->root_dev))) +- { +- /* Change detected; disable reloading. */ +- atomic_store_release (&local->data.reload_disabled, 1); +- __libc_lock_unlock (local->lock); +- __nss_module_disable_loading (); +- return true; +- } +- local->root_ino = str.st_ino; +- local->root_dev = str.st_dev; +- __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_database_state); +- 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_database_state); +- global_database_state = 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_database_state); +- 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_database_state); +- 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_database_state = NULL; +-} +Index: glibc-2.33/nss/nss_database.h +=================================================================== +--- glibc-2.33.orig/nss/nss_database.h ++++ /dev/null +@@ -1,88 +0,0 @@ +-/* Mapping NSS services to action lists. +- Copyright (C) 2020-2021 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 +- +-/* Each "line" in nsswitch.conf maps a supported database (example: +- passwd) to one or more name service providers (example: files dns). +- Internally, each name service provider (example: dns) is a +- dynamically loadable module (i.e. libnss_dns.so), managed by +- nss_module.h. The sequence of providers and rules (example: files +- [SUCCESS=RETURN] dns) is mapped by nss_action.h to a cached entry +- which encodes the sequence of modules and rules. Keeping track of +- all supported databases and their corresponding actions is done +- here. +- +- The key entry is __nss_database_get, which provides a set of +- actions which can be used with nss_lookup_function() and +- nss_next(). Callers should assume that these functions are fast, +- and should not cache the result longer than needed. */ +- +-#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 */ +Index: glibc-2.33/nss/nss_module.c +=================================================================== +--- glibc-2.33.orig/nss/nss_module.c ++++ /dev/null +@@ -1,379 +0,0 @@ +-/* Global list of NSS service modules. +- Copyright (c) 2020-2021 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 +-#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. This is a bit of magic, +- but we assume LIBNSS_FILES_SO looks like "libnss_files.so.2" and we +- want a pointer to the ".2" part. We have no API to extract this +- except through the auto-generated lib-names.h and some static +- pointer manipulation. The "-1" accounts for the trailing NUL +- included in the sizeof. */ +-static const char *const __nss_shlib_revision +- = LIBNSS_FILES_SO + sizeof("libnss_files.so") - 1; +- +-/* A single-linked list used to implement a mapping from service names +- to NSS modules. (Most systems only use five or so 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); +- +-#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 +- +-/* Allocate the service NAME with length NAME_LENGTH. If the service +- is already allocated in the nss_module_list cache then we return a +- pointer to the struct nss_module, otherwise we try to allocate a +- new struct nss_module entry and add it to the global +- nss_modules_list cache. If we fail to allocate the entry we return +- NULL. Failure to allocate the entry is always transient. */ +-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 in the +- nss_function_name_array list below, as getprotobynumber_r is the +- longest entry in that list. */ +-typedef char function_name[sizeof("getprotobynumber_r")]; +- +-static const function_name nss_function_name_array[] = +- { +-#undef DEFINE_NSS_FUNCTION +-#define DEFINE_NSS_FUNCTION(x) #x, +-#include "function.def" +- }; +- +-/* Internal implementation of __nss_module_load. */ +-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); +- } +- +- /* Failing to load the module can be caused by several different +- scenarios. One such scenario is that the module has been removed +- from the disk. In which case the in-memory version is all that +- we have, and if the module->state indidates it is loaded then we +- can use it. */ +- 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; +- +- /* Look up and store locally all the function pointers we may need +- later. Doing this now means the data will not change in the +- future. */ +- 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 +- } +- +-# 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 +- +- /* Install 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; +- /* Synchronizes with unlocked __nss_module_load atomic_load_acquire. */ +- atomic_store_release (&module->state, nss_module_loaded); +- break; +- case nss_module_loaded: +- /* If the module was already loaded, close our own handle. This +- does not actually unload the modules, only the reference +- counter is decremented for the loaded module. */ +- __libc_dlclose (handle); +- break; +- } +- __libc_lock_unlock (nss_module_list_lock); +- return true; +-} +- +-/* Force the module identified by MODULE to be loaded. We return +- false if the module could not be loaded, true otherwise. Loading +- the module requires looking up all the possible interface APIs and +- caching the results. */ +-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); +-} +- +-/* Load module MODULE (if it isn't already) and return a pointer to +- the module's implementation of NAME, otherwise return NULL on +- failure or error. */ +-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; +-} +- +-#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 +- +-/* Block attempts to dlopen any module we haven't already opened. */ +-void +-__nss_module_disable_loading (void) +-{ +- __libc_lock_lock (nss_module_list_lock); +- +- for (struct nss_module *p = nss_module_list; p != NULL; p = p->next) +- if (p->state == nss_module_uninitialized) +- p->state = nss_module_failed; +- +- __libc_lock_unlock (nss_module_list_lock); +-} +- +-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; +-} +Index: glibc-2.33/nss/nss_module.h +=================================================================== +--- glibc-2.33.orig/nss/nss_module.h ++++ /dev/null +@@ -1,96 +0,0 @@ +-/* Global list of NSS service modules. +- Copyright (c) 2020-2021 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 +- +-/* See nss_database.h for a summary of how this relates. */ +- +-/* Typed function pointers for all functions that can be defined by a +- service module. */ +-struct nss_module_functions +-{ +-#undef DEFINE_NSS_FUNCTION +-#define DEFINE_NSS_FUNCTION(f) nss_##f *f; +-#include "function.def" +-}; +- +-/* 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; +- +-/* Block attempts to dlopen any module we haven't already opened. */ +-void __nss_module_disable_loading (void); +- +-/* Called from __libc_freeres. */ +-void __nss_module_freeres (void) attribute_hidden; +- +-#endif /* NSS_MODULE_H */ +Index: glibc-2.33/nss/nss_test.h +=================================================================== +--- glibc-2.33.orig/nss/nss_test.h ++++ glibc-2.33/nss/nss_test.h +@@ -33,12 +33,10 @@ + + #include + #include +-#include + + typedef struct test_tables { + struct passwd *pwd_table; + struct group *grp_table; +- struct hostent *host_table; + } test_tables; + + extern void _nss_test1_init_hook (test_tables *) __attribute__((weak)); +@@ -46,11 +44,9 @@ extern void _nss_test2_init_hook (test_t + + #define PWD_LAST() { .pw_name = NULL, .pw_uid = 0 } + #define GRP_LAST() { .gr_name = NULL, .gr_gid = 0 } +-#define HOST_LAST() { .h_name = NULL, .h_aliases = NULL, .h_length = 0, .h_addr_list = NULL } + + #define PWD_ISLAST(p) ((p)->pw_name == NULL && (p)->pw_uid == 0) + #define GRP_ISLAST(g) ((g)->gr_name == NULL && (g)->gr_gid == 0) +-#define HOST_ISLAST(h) ((h)->h_name == NULL && (h)->h_length == 0) + + /* Macros to fill in the tables easily. */ + +@@ -76,11 +72,6 @@ extern void _nss_test2_init_hook (test_t + { .gr_name = (char *) n, .gr_passwd = (char *) "*", .gr_gid = u, \ + .gr_mem = (char **) m } + +-#define HOST(u) \ +- { .h_name = (char *) "name" #u, .h_aliases = NULL, .h_addrtype = u, \ +- .h_length = 4, \ +- .h_addr_list = (char **) hostaddr_##u } +- + /*------------------------------------------------------------*/ + + /* Helper functions for testing passwd entries. Call +Index: glibc-2.33/nss/nss_test1.c +=================================================================== +--- glibc-2.33.orig/nss/nss_test1.c ++++ glibc-2.33/nss/nss_test1.c +@@ -66,9 +66,6 @@ static int npwd_data = default_npwd_data + static struct group *grp_data = NULL; + static int ngrp_data = 0; + +-static struct hostent *host_data = NULL; +-static int nhost_data = 0; +- + /* This function will get called, and once per session, look back into + the test case's executable for an init hook function, and call + it. */ +@@ -102,13 +99,6 @@ init(void) + ; + ngrp_data = i; + } +- if (t.host_table) +- { +- host_data = t.host_table; +- for (i=0; ! HOST_ISLAST(& host_data[i]); i++) +- ; +- nhost_data = i; +- } + } + initted = 1; + } +@@ -290,7 +280,7 @@ NAME(getgrent_r) (struct group *result, + ++grp_iter; + } + +- pthread_mutex_unlock (&grp_lock); ++ pthread_mutex_unlock (&pwd_lock); + + return res; + } +@@ -322,157 +312,3 @@ NAME(getgrnam_r) (const char *name, stru + + return NSS_STATUS_NOTFOUND; + } +- +-/* -------------------------------------------------- */ +-/* Host handling. */ +- +-static size_t host_iter; +-#define CURHOST host_data[host_iter] +- +-static pthread_mutex_t host_lock = PTHREAD_MUTEX_INITIALIZER; +- +-enum nss_status +-NAME(sethostent) (int stayopen) +-{ +- init(); +- host_iter = 0; +- return NSS_STATUS_SUCCESS; +-} +- +- +-enum nss_status +-NAME(endhostent) (void) +-{ +- init(); +- return NSS_STATUS_SUCCESS; +-} +- +-static enum nss_status +-copy_host (struct hostent *result, struct hostent *local, +- char *buffer, size_t buflen, int *errnop) +-{ +- struct alloc_buffer buf = alloc_buffer_create (buffer, buflen); +- char **memlist; +- int i, j; +- +- if (local->h_addr_list) +- { +- i = 0; +- while (local->h_addr_list[i]) +- ++i; +- +- memlist = alloc_buffer_alloc_array (&buf, char *, i + 1); +- +- if (memlist) { +- for (j = 0; j < i; ++j) +- memlist[j] = alloc_buffer_maybe_copy_string (&buf, local->h_addr_list[j]); +- memlist[j] = NULL; +- } +- +- result->h_addr_list = memlist; +- } +- else +- { +- result->h_addr_list = NULL; +- } +- +- result->h_aliases = NULL; +- result->h_addrtype = AF_INET; +- result->h_length = 4; +- result->h_name = alloc_buffer_maybe_copy_string (&buf, local->h_name); +- +- if (alloc_buffer_has_failed (&buf)) +- { +- *errnop = ERANGE; +- return NSS_STATUS_TRYAGAIN; +- } +- +- return NSS_STATUS_SUCCESS; +-} +- +- +-enum nss_status +-NAME(gethostent_r) (struct hostent *ret, char *buffer, size_t buflen, +- struct hostent **result, int *errnop) +-{ +- int res = NSS_STATUS_SUCCESS; +- +- init(); +- pthread_mutex_lock (&host_lock); +- +- if (host_iter >= nhost_data) +- { +- res = NSS_STATUS_NOTFOUND; +- *result = NULL; +- } +- else +- { +- res = copy_host (ret, &CURHOST, buffer, buflen, errnop); +- *result = ret; +- ++host_iter; +- } +- +- pthread_mutex_unlock (&host_lock); +- +- return res; +-} +- +-enum nss_status +-NAME(gethostbyname3_r) (const char *name, int af, struct hostent *ret, +- char *buffer, size_t buflen, int *errnop, +- int *h_errnop, int32_t *ttlp, char **canonp) +-{ +- init(); +- +- for (size_t idx = 0; idx < nhost_data; ++idx) +- if (strcmp (host_data[idx].h_name, name) == 0) +- return copy_host (ret, & host_data[idx], buffer, buflen, h_errnop); +- +- return NSS_STATUS_NOTFOUND; +-} +- +-enum nss_status +-NAME(gethostbyname_r) (const char *name, struct hostent *result, +- char *buffer, size_t buflen, +- int *errnop, int *h_errnop) +-{ +- return NAME(gethostbyname3_r) (name, AF_INET, result, buffer, buflen, +- errnop, h_errnop, NULL, NULL); +-} +- +-enum nss_status +-NAME(gethostbyname2_r) (const char *name, int af, struct hostent *result, +- char *buffer, size_t buflen, +- int *errnop, int *h_errnop) +-{ +- return NAME(gethostbyname3_r) (name, af, result, buffer, buflen, +- errnop, h_errnop, NULL, NULL); +-} +- +-enum nss_status +-NAME(gethostbyaddr2_r) (const void *addr, socklen_t len, int af, +- struct hostent *result, char *buffer, size_t buflen, +- int *errnop, int *h_errnop, int32_t *ttlp) +-{ +- init(); +- +- /* Support this later. */ +- if (len != 4) +- return NSS_STATUS_NOTFOUND; +- +- for (size_t idx = 0; idx < nhost_data; ++idx) +- if (memcmp (host_data[idx].h_addr, addr, len) == 0) +- return copy_host (result, & host_data[idx], buffer, buflen, h_errnop); +- +- return NSS_STATUS_NOTFOUND; +-} +- +-/* Note: only the first address is supported, intentionally. */ +-enum nss_status +-NAME(gethostbyaddr_r) (const void *addr, socklen_t len, int af, +- struct hostent *result, char *buffer, size_t buflen, +- int *errnop, int *h_errnop) +-{ +- return NAME(gethostbyaddr2_r) (addr, len, af, result, buffer, buflen, +- errnop, h_errnop, NULL); +-} +Index: glibc-2.33/nss/nsswitch.c +=================================================================== +--- glibc-2.33.orig/nss/nsswitch.c ++++ glibc-2.33/nss/nsswitch.c +@@ -32,7 +32,6 @@ + #include + #include + #include +-#include + + #if !defined DO_STATIC_NSS || defined SHARED + # include +@@ -43,20 +42,36 @@ + #include + #include + ++/* 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) \ +- nss_action_list __nss_##name##_database attribute_hidden; \ ++ service_user *__nss_##name##_database attribute_hidden; \ + weak_extern (__nss_##name##_database) + #include "databases.def" + #undef DEFINE_DATABASE + +- +-#undef DEFINE_DATABASE +-#define DEFINE_DATABASE(name) #name, +-static const char * database_names[] = { ++/* 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" +- NULL ++#undef DEFINE_DATABASE + }; ++#define ndatabases (sizeof (databases) / sizeof (databases[0])) + + #ifdef USE_NSCD + /* Flags whether custom rules for database is set. */ +@@ -64,36 +79,103 @@ bool __nss_database_custom[NSS_DBSIDX_ma + #endif + + +-/*__libc_lock_define_initialized (static, lock)*/ ++__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 ++ + + /* -1 == database not found + 0 == database entry pointer stored */ + int + __nss_database_lookup2 (const char *database, const char *alternate_name, +- const char *defconfig, nss_action_list *ni) ++ const char *defconfig, service_user **ni) + { +- int database_id; ++ /* Prevent multiple threads to change the service table. */ ++ __libc_lock_lock (lock); + +- for (database_id = 0; database_names[database_id]; database_id++) +- if (strcmp (database_names[database_id], database) == 0) +- break; ++ /* 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; ++ } + +- if (database_names[database_id] == NULL) +- return -1; ++ /* Are we initialized yet? */ ++ if (service_table == NULL) ++ /* Read config file. */ ++ service_table = nss_parse_file (_PATH_NSSWITCH_CONF); + +- /* If *NI is NULL, the database was not mentioned in nsswitch.conf. +- If *NI is not NULL, but *NI->module is NULL, the database was in +- nsswitch.conf but listed no actions. We test for the former. */ +- if (__nss_database_get (database_id, ni) && *ni != NULL) ++ /* Test whether configuration data is available. */ ++ if (service_table != NULL) + { +- /* Success. */ +- return 0; ++ /* 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; + } +- else ++ ++ /* 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) + { +- /* Failure. */ +- return -1; ++ *ni = nss_parse_service_list (defconfig ?: "files"); ++ if (*ni != NULL) ++ { ++ /* Record the memory we've just allocated in defconfig_entries list, ++ so we can free it later. */ ++ name_database_entry *entry; ++ ++ /* Allocate ENTRY plus size of name (1 here). */ ++ entry = (name_database_entry *) malloc (sizeof (*entry) + 1); ++ ++ if (entry != NULL) ++ { ++ entry->next = defconfig_entries; ++ entry->service = *ni; ++ entry->name[0] = '\0'; ++ defconfig_entries = entry; ++ } ++ } + } ++ ++ __libc_lock_unlock (lock); ++ ++ return *ni != NULL ? 0 : -1; + } + libc_hidden_def (__nss_database_lookup2) + +@@ -102,7 +184,7 @@ libc_hidden_def (__nss_database_lookup2) + 0 == function found + 1 == finished */ + int +-__nss_lookup (nss_action_list *ni, const char *fct_name, const char *fct2_name, ++__nss_lookup (service_user **ni, const char *fct_name, const char *fct2_name, + void **fctp) + { + *fctp = __nss_lookup_function (*ni, fct_name); +@@ -111,16 +193,16 @@ __nss_lookup (nss_action_list *ni, const + + while (*fctp == NULL + && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE +- && (*ni)[1].module != NULL) ++ && (*ni)->next != NULL) + { +- ++(*ni); ++ *ni = (*ni)->next; + + *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)[1].module == NULL ? 1 : -1; ++ return *fctp != NULL ? 0 : (*ni)->next == NULL ? 1 : -1; + } + libc_hidden_def (__nss_lookup) + +@@ -129,7 +211,7 @@ libc_hidden_def (__nss_lookup) + 0 == adjusted for next function + 1 == finished */ + int +-__nss_next2 (nss_action_list *ni, const char *fct_name, const char *fct2_name, ++__nss_next2 (service_user **ni, const char *fct_name, const char *fct2_name, + void **fctp, int status, int all_values) + { + if (all_values) +@@ -151,12 +233,12 @@ __nss_next2 (nss_action_list *ni, const + return 1; + } + +- if ((*ni)[1].module == NULL) ++ if ((*ni)->next == NULL) + return -1; + + do + { +- ++(*ni); ++ *ni = (*ni)->next; + + *fctp = __nss_lookup_function (*ni, fct_name); + if (*fctp == NULL && fct2_name != NULL) +@@ -164,17 +246,675 @@ __nss_next2 (nss_action_list *ni, const + } + while (*fctp == NULL + && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE +- && (*ni)[1].module != NULL); ++ && (*ni)->next != 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 (nss_action_list ni, const char *fct_name) ++__nss_lookup_function (service_user *ni, const char *fct_name) + { +- if (ni->module == NULL) +- return NULL; +- return __nss_module_get_function (ni->module, 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) ++{ ++ 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) ++ 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", "files"); ++ nss_load_all_libraries ("group", "files"); ++ nss_load_all_libraries ("hosts", "dns [!UNAVAIL=return] files"); ++ nss_load_all_libraries ("services", NULL); ++ ++ /* Disable all uses of NSCD. */ ++ __nss_not_use_nscd_passwd = -1; ++ __nss_not_use_nscd_group = -1; ++ __nss_not_use_nscd_hosts = -1; ++ __nss_not_use_nscd_services = -1; ++ __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); ++} +Index: glibc-2.33/nss/nsswitch.h +=================================================================== +--- glibc-2.33.orig/nss/nsswitch.h ++++ glibc-2.33/nss/nsswitch.h +@@ -36,7 +36,6 @@ typedef enum + NSS_ACTION_MERGE + } lookup_actions; + +-struct nss_action; + + typedef struct service_library + { +@@ -59,8 +58,42 @@ typedef struct + } known_function; + + ++typedef struct service_user ++{ ++ /* And the link to the next entry. */ ++ struct service_user *next; ++ /* Action according to result. */ ++ lookup_actions actions[5]; ++ /* Link to the underlying library object. */ ++ service_library *library; ++ /* Collection of known functions. */ ++ void *known; ++ /* Name of the service (`files', `dns', `nis', ...). */ ++ char name[0]; ++} service_user; ++ + /* To access the action based on the status value use this macro. */ +-#define nss_next_action(ni, status) nss_action_get (ni, status) ++#define nss_next_action(ni, status) ((ni)->actions[2 + status]) ++ ++ ++typedef struct name_database_entry ++{ ++ /* And the link to the next entry. */ ++ struct name_database_entry *next; ++ /* List of service to be used. */ ++ service_user *service; ++ /* Name of the database. */ ++ char name[0]; ++} name_database_entry; ++ ++ ++typedef struct name_database ++{ ++ /* List of all known databases. */ ++ name_database_entry *entry; ++ /* List of libraries with service implementation. */ ++ service_library *library; ++} name_database; + + + #ifdef USE_NSCD +@@ -94,13 +127,13 @@ extern bool __nss_database_custom[NSS_DB + than one function can use the database. */ + extern int __nss_database_lookup2 (const char *database, + const char *alternative_name, +- const char *defconfig, struct nss_action **ni); ++ const char *defconfig, service_user **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 (struct nss_action **ni, const char *fct_name, ++extern int __nss_lookup (service_user **ni, const char *fct_name, + const char *fct2_name, void **fctp); + libc_hidden_proto (__nss_lookup) + +@@ -117,16 +150,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 (struct nss_action **ni, const char *fct_name, ++extern int __nss_next2 (service_user **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 (struct nss_action **ni, const char *fct_name, void **fctp, ++extern int __nss_next (service_user **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 (struct nss_action *ni, const char *fct_name); ++extern void *__nss_lookup_function (service_user *ni, const char *fct_name); + libc_hidden_proto (__nss_lookup_function) + + +@@ -136,7 +169,7 @@ struct traced_file; + extern void __nss_disable_nscd (void (*) (size_t, struct traced_file *)); + + +-typedef int (*db_lookup_function) (struct nss_action **, const char *, const char *, ++typedef int (*db_lookup_function) (service_user **, const char *, const char *, + void **); + typedef enum nss_status (*setent_function) (int); + typedef enum nss_status (*endent_function) (void); +@@ -147,20 +180,20 @@ typedef int (*getent_r_function) (void * + + extern void __nss_setent (const char *func_name, + db_lookup_function lookup_fct, +- struct nss_action **nip, struct nss_action **startp, +- struct nss_action **last_nip, int stayon, ++ service_user **nip, service_user **startp, ++ service_user **last_nip, int stayon, + int *stayon_tmp, int res) + attribute_hidden; + extern void __nss_endent (const char *func_name, + db_lookup_function lookup_fct, +- struct nss_action **nip, struct nss_action **startp, +- struct nss_action **last_nip, int res) ++ service_user **nip, service_user **startp, ++ service_user **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, +- struct nss_action **nip, struct nss_action **startp, +- struct nss_action **last_nip, int *stayon_tmp, ++ service_user **nip, service_user **startp, ++ service_user **last_nip, int *stayon_tmp, + int res, + void *resbuf, char *buffer, size_t buflen, + void **result, int *h_errnop) +@@ -194,15 +227,11 @@ libc_hidden_proto (__nss_hostname_digits + + /* Prototypes for __nss_*_lookup2 functions. */ + #define DEFINE_DATABASE(arg) \ +- extern struct nss_action *__nss_##arg##_database attribute_hidden; \ +- int __nss_##arg##_lookup2 (struct nss_action **, const char *, \ ++ extern service_user *__nss_##arg##_database attribute_hidden; \ ++ int __nss_##arg##_lookup2 (service_user **, const char *, \ + const char *, void **); \ + libc_hidden_proto (__nss_##arg##_lookup2) + #include "databases.def" + #undef DEFINE_DATABASE + +-#include +-#include +-#include +- + #endif /* nsswitch.h */ +Index: glibc-2.33/nss/tst-reload1.c +=================================================================== +--- glibc-2.33.orig/nss/tst-reload1.c ++++ /dev/null +@@ -1,341 +0,0 @@ +-/* Test that nsswitch.conf reloading actually works. +- Copyright (C) 2020-2021 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 "nss_test.h" +- +-/* Size of buffers used by *_r functions. */ +-#define TESTBUFLEN 4096 +- +-static struct passwd pwd_table_1[] = { +- PWD (100), +- PWD (30), +- PWD (200), +- PWD (60), +- PWD (20000), +- PWD_LAST () +- }; +- +-static const char *hostaddr_5[] = +- { +- "ABCD", "abcd", "1234", NULL +- }; +- +-static const char *hostaddr_15[] = +- { +- "4321", "ghij", NULL +- }; +- +-static const char *hostaddr_25[] = +- { +- "WXYZ", NULL +- }; +- +- +-static struct hostent host_table_1[] = { +- HOST (5), +- HOST (15), +- HOST (25), +- HOST_LAST () +-}; +- +-void +-_nss_test1_init_hook(test_tables *t) +-{ +- t->pwd_table = pwd_table_1; +- t->host_table = host_table_1; +-} +- +-/* The first of these must not appear in pwd_table_1. */ +-static struct passwd pwd_table_2[] = { +- PWD (5), +- PWD_N(200, "name30"), +- PWD (16), +- PWD_LAST () +- }; +- +-static const char *hostaddr_6[] = +- { +- "mnop", NULL +- }; +- +-static const char *hostaddr_16[] = +- { +- "7890", "a1b2", NULL +- }; +- +-static const char *hostaddr_26[] = +- { +- "qwer", "tyui", NULL +- }; +- +-static struct hostent host_table_2[] = { +- HOST (6), +- HOST (16), +- HOST (26), +- HOST_LAST () +-}; +- +-void +-_nss_test2_init_hook(test_tables *t) +-{ +- t->pwd_table = pwd_table_2; +- t->host_table = host_table_2; +-} +- +-static void +-must_be_tests (struct passwd *pt, struct hostent *ht) +-{ +- int i; +- struct hostent *h; +- +- struct passwd *p; +- for (i = 0; !PWD_ISLAST (&pt[i]); ++i) +- { +- p = getpwuid (pt[i].pw_uid); +- TEST_VERIFY (p != NULL); +- if (p != NULL) +- { +- TEST_VERIFY (strcmp (p->pw_name, pt[i].pw_name) == 0); +- } +- } +- +- setpwent (); +- for (i = 0; !PWD_ISLAST (&pt[i]); ++i) +- { +- p = getpwent (); +- TEST_VERIFY (p != NULL); +- if (p != NULL) +- { +- TEST_VERIFY (strcmp (p->pw_name, pt[i].pw_name) == 0); +- TEST_VERIFY (p->pw_uid == pt[i].pw_uid); +- } +- } +- endpwent (); +- +- for (i = 0; !HOST_ISLAST (&ht[i]); ++i) +- { +- h = gethostbyname (ht[i].h_name); +- TEST_VERIFY (h != NULL); +- if (h != NULL) +- { +- TEST_VERIFY (strcmp (h->h_name, ht[i].h_name) == 0); +- TEST_VERIFY (h->h_addr_list[0] != NULL); +- if (h->h_addr_list[0]) +- TEST_VERIFY (strcmp (h->h_addr_list[0], ht[i].h_addr_list[0]) == 0); +- } +- } +- +- for (i = 0; !HOST_ISLAST (&ht[i]); ++i) +- { +- struct hostent r, *rp; +- char buf[TESTBUFLEN]; +- int herrno, res; +- +- res = gethostbyname2_r (ht[i].h_name, AF_INET, +- &r, buf, TESTBUFLEN, &rp, &herrno); +- TEST_VERIFY (res == 0); +- if (res == 0) +- { +- TEST_VERIFY (strcmp (r.h_name, ht[i].h_name) == 0); +- TEST_VERIFY (r.h_addr_list[0] != NULL); +- if (r.h_addr_list[0]) +- TEST_VERIFY (strcmp (r.h_addr_list[0], ht[i].h_addr_list[0]) == 0); +- } +- } +- +- for (i = 0; !HOST_ISLAST (&ht[i]); ++i) +- { +- h = gethostbyaddr (ht[i].h_addr, 4, AF_INET); +- TEST_VERIFY (h != NULL); +- if (h != NULL) +- { +- TEST_VERIFY (strcmp (h->h_name, ht[i].h_name) == 0); +- TEST_VERIFY (h->h_addr_list[0] != NULL); +- if (h->h_addr_list[0]) +- TEST_VERIFY (strcmp (h->h_addr_list[0], ht[i].h_addr_list[0]) == 0); +- } +- } +- +- /* getaddrinfo */ +- +- for (i = 0; !HOST_ISLAST (&ht[i]); ++i) +- { +- struct addrinfo *ap; +- struct addrinfo hint; +- int res, j; +- +- memset (&hint, 0, sizeof (hint)); +- hint.ai_family = AF_INET; +- hint.ai_socktype = SOCK_STREAM; +- hint.ai_protocol = 0; +- hint.ai_flags = 0; +- +- ap = NULL; +- res = getaddrinfo (ht[i].h_name, NULL, &hint, &ap); +- TEST_VERIFY (res == 0); +- TEST_VERIFY (ap != NULL); +- if (res == 0 && ap != NULL) +- { +- j = 0; /* which address in the list */ +- while (ap) +- { +- struct sockaddr_in *in = (struct sockaddr_in *)ap->ai_addr; +- unsigned char *up = (unsigned char *)&in->sin_addr; +- +- TEST_VERIFY (memcmp (up, ht[i].h_addr_list[j], 4) == 0); +- +- ap = ap->ai_next; +- ++j; +- } +- } +- } +- +- /* getnameinfo */ +- +- for (i = 0; !HOST_ISLAST (&ht[i]); ++i) +- { +- struct sockaddr_in addr; +- int res; +- char host_buf[NI_MAXHOST]; +- +- memset (&addr, 0, sizeof (addr)); +- addr.sin_family = AF_INET; +- addr.sin_port = 80; +- memcpy (& addr.sin_addr, ht[i].h_addr_list[0], 4); +- +- res = getnameinfo ((struct sockaddr *) &addr, sizeof(addr), +- host_buf, sizeof(host_buf), +- NULL, 0, NI_NOFQDN); +- +- TEST_VERIFY (res == 0); +- if (res == 0) +- TEST_VERIFY (strcmp (ht[i].h_name, host_buf) == 0); +- else +- printf ("error %s\n", gai_strerror (res)); +- } +-} +- +-static void +-must_be_1 (void) +-{ +- struct passwd *p; +- +- must_be_tests (pwd_table_1, host_table_1); +- p = getpwnam("name5"); +- TEST_VERIFY (p == NULL); +-} +- +-static void +-must_be_2 (void) +-{ +- struct passwd *p; +- +- must_be_tests (pwd_table_2, host_table_2); +- p = getpwnam("name100"); +- TEST_VERIFY (p == NULL); +-} +- +-static void +-xrename (const char *a, const char *b) +-{ +- int i = rename (a, b); +- if (i != 0) +- FAIL_EXIT1 ("rename(%s,%s) failed: %s\n", a, b, strerror(errno)); +-} +- +-/* If the actions change while in the midst of doing a series of +- lookups, make sure they're consistent. */ +-static void +-test_cross_switch_consistency (void) +-{ +- int i; +- struct passwd *p; +- +- /* We start by initiating a set/get/end loop on conf1. */ +- setpwent (); +- for (i = 0; !PWD_ISLAST (&pwd_table_1[i]); ++i) +- { +- p = getpwent (); +- TEST_VERIFY (p != NULL); +- if (p != NULL) +- { +- TEST_VERIFY (strcmp (p->pw_name, pwd_table_1[i].pw_name) == 0); +- TEST_VERIFY (p->pw_uid == pwd_table_1[i].pw_uid); +- } +- +- /* After the first lookup, switch to conf2 and verify */ +- if (i == 0) +- { +- xrename ("/etc/nsswitch.conf", "/etc/nsswitch.conf1"); +- xrename ("/etc/nsswitch.conf2", "/etc/nsswitch.conf"); +- +- p = getpwnam (pwd_table_2[0].pw_name); +- TEST_VERIFY (p->pw_uid == pwd_table_2[0].pw_uid); +- } +- +- /* But the original loop should still be on conf1. */ +- } +- endpwent (); +- +- /* Make sure the set/get/end loop sees conf2 now. */ +- setpwent (); +- for (i = 0; !PWD_ISLAST (&pwd_table_2[i]); ++i) +- { +- p = getpwent (); +- TEST_VERIFY (p != NULL); +- if (p != NULL) +- { +- TEST_VERIFY (strcmp (p->pw_name, pwd_table_2[i].pw_name) == 0); +- TEST_VERIFY (p->pw_uid == pwd_table_2[i].pw_uid); +- } +- } +- endpwent (); +- +-} +- +-static int +-do_test (void) +-{ +- /* The test1 module was configured at program start. */ +- must_be_1 (); +- +- xrename ("/etc/nsswitch.conf", "/etc/nsswitch.conf1"); +- xrename ("/etc/nsswitch.conf2", "/etc/nsswitch.conf"); +- must_be_2 (); +- +- xrename ("/etc/nsswitch.conf", "/etc/nsswitch.conf2"); +- xrename ("/etc/nsswitch.conf1", "/etc/nsswitch.conf"); +- must_be_1 (); +- +- test_cross_switch_consistency (); +- +- return 0; +-} +- +-#include +Index: glibc-2.33/nss/tst-reload1.root/etc/nsswitch.conf +=================================================================== +--- glibc-2.33.orig/nss/tst-reload1.root/etc/nsswitch.conf ++++ /dev/null +@@ -1,3 +0,0 @@ +-passwd: test1 +-group: test1 +-hosts: test1 +Index: glibc-2.33/nss/tst-reload1.root/etc/nsswitch.conf2 +=================================================================== +--- glibc-2.33.orig/nss/tst-reload1.root/etc/nsswitch.conf2 ++++ /dev/null +@@ -1,3 +0,0 @@ +-passwd: test2 +-group: test2 +-hosts: test2 +Index: glibc-2.33/nss/tst-reload1.root/etc/services +=================================================================== +--- glibc-2.33.orig/nss/tst-reload1.root/etc/services ++++ /dev/null +@@ -1 +0,0 @@ +-http 80/tcp +Index: glibc-2.33/nss/tst-reload1.root/tst-reload1.script +=================================================================== +--- glibc-2.33.orig/nss/tst-reload1.root/tst-reload1.script ++++ /dev/null +@@ -1,2 +0,0 @@ +-cp $B/nss/libnss_test1.so $L/libnss_test1.so.2 +-cp $B/nss/libnss_test2.so $L/libnss_test2.so.2 +Index: glibc-2.33/nss/tst-reload2.c +=================================================================== +--- glibc-2.33.orig/nss/tst-reload2.c ++++ /dev/null +@@ -1,130 +0,0 @@ +-/* Test that reloading is disabled after a chroot. +- Copyright (C) 2020-2021 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 +-#include +-#include +- +-#include "nss_test.h" +- +-#ifndef PATH_MAX +-# define PATH_MAX 1024 +-#endif +- +-static struct passwd pwd_table1[] = +- { +- PWD_N (1234, "test1"), +- PWD_N (4321, "test2"), +- PWD_LAST () +- }; +- +-static const char *group_4[] = { +- "alpha", "beta", "gamma", "fred", NULL +-}; +- +-static struct group group_table_data[] = +- { +- GRP (4), +- GRP_LAST () +- }; +- +-void +-_nss_test1_init_hook (test_tables *t) +-{ +- t->pwd_table = pwd_table1; +- t->grp_table = group_table_data; +-} +- +-static struct passwd pwd_table2[] = +- { +- PWD_N (5, "test1"), +- PWD_N (2468, "test2"), +- PWD_LAST () +- }; +- +-void +-_nss_test2_init_hook (test_tables *t) +-{ +- t->pwd_table = pwd_table2; +-} +- +-static int +-do_test (void) +-{ +- struct passwd *pw; +- struct group *gr; +- char buf1[PATH_MAX]; +- char buf2[PATH_MAX]; +- +- sprintf (buf1, "/subdir%s", support_slibdir_prefix); +- xmkdirp (buf1, 0777); +- +- /* Copy this DSO into the chroot so it *could* be loaded. */ +- sprintf (buf1, "%s/libnss_files.so.2", support_slibdir_prefix); +- sprintf (buf2, "/subdir%s/libnss_files.so.2", support_slibdir_prefix); +- support_copy_file (buf1, buf2); +- +- /* Check we're using the "outer" nsswitch.conf. */ +- +- /* This uses the test1 DSO. */ +- pw = getpwnam ("test1"); +- TEST_VERIFY (pw != NULL); +- if (pw) +- TEST_COMPARE (pw->pw_uid, 1234); +- +- /* This just loads the test2 DSO. */ +- gr = getgrnam ("name4"); +- +- /* Change the root dir. */ +- +- TEST_VERIFY (chroot ("/subdir") == 0); +- chdir ("/"); +- +- /* Check we're NOT using the "inner" nsswitch.conf. */ +- +- /* Both DSOs are loaded, which is used? */ +- pw = getpwnam ("test2"); +- TEST_VERIFY (pw != NULL); +- if (pw) +- TEST_VERIFY (pw->pw_uid != 2468); +- +- /* The "files" DSO should not be loaded. */ +- gr = getgrnam ("test3"); +- TEST_VERIFY (gr == NULL); +- +- /* We should still be using the old configuration. */ +- pw = getpwnam ("test1"); +- TEST_VERIFY (pw != NULL); +- if (pw) +- TEST_COMPARE (pw->pw_uid, 1234); +- +- return 0; +-} +- +-#include +Index: glibc-2.33/nss/tst-reload2.root/etc/nsswitch.conf +=================================================================== +--- glibc-2.33.orig/nss/tst-reload2.root/etc/nsswitch.conf ++++ /dev/null +@@ -1,2 +0,0 @@ +-passwd: test1 +-group: test2 +Index: glibc-2.33/nss/tst-reload2.root/subdir/etc/group +=================================================================== +--- glibc-2.33.orig/nss/tst-reload2.root/subdir/etc/group ++++ /dev/null +@@ -1 +0,0 @@ +-test3:x:123: +Index: glibc-2.33/nss/tst-reload2.root/subdir/etc/nsswitch.conf +=================================================================== +--- glibc-2.33.orig/nss/tst-reload2.root/subdir/etc/nsswitch.conf ++++ /dev/null +@@ -1,2 +0,0 @@ +-passwd: test2 +-group: files +Index: glibc-2.33/nss/tst-reload2.root/tst-reload2.script +=================================================================== +--- glibc-2.33.orig/nss/tst-reload2.root/tst-reload2.script ++++ /dev/null +@@ -1,3 +0,0 @@ +-su +-cp $B/nss/libnss_test1.so $L/libnss_test1.so.2 +-cp $B/nss/libnss_test2.so $L/libnss_test2.so.2 +Index: glibc-2.33/posix/tst-rfc3484-2.c +=================================================================== +--- glibc-2.33.orig/posix/tst-rfc3484-2.c ++++ glibc-2.33/posix/tst-rfc3484-2.c +@@ -58,7 +58,7 @@ _res_hconf_init (void) + #undef USE_NSCD + #include "../sysdeps/posix/getaddrinfo.c" + +-nss_action_list __nss_hosts_database attribute_hidden; ++service_user *__nss_hosts_database attribute_hidden; + + /* This is the beginning of the real test code. The above defines + (among other things) the function rfc3484_sort. */ +Index: glibc-2.33/posix/tst-rfc3484-3.c +=================================================================== +--- glibc-2.33.orig/posix/tst-rfc3484-3.c ++++ glibc-2.33/posix/tst-rfc3484-3.c +@@ -58,7 +58,7 @@ _res_hconf_init (void) + #undef USE_NSCD + #include "../sysdeps/posix/getaddrinfo.c" + +-nss_action_list __nss_hosts_database attribute_hidden; ++service_user *__nss_hosts_database attribute_hidden; + + /* This is the beginning of the real test code. The above defines + (among other things) the function rfc3484_sort. */ +Index: glibc-2.33/posix/tst-rfc3484.c +=================================================================== +--- glibc-2.33.orig/posix/tst-rfc3484.c ++++ glibc-2.33/posix/tst-rfc3484.c +@@ -58,7 +58,7 @@ _res_hconf_init (void) + #undef USE_NSCD + #include "../sysdeps/posix/getaddrinfo.c" + +-nss_action_list __nss_hosts_database attribute_hidden; ++service_user *__nss_hosts_database attribute_hidden; + + /* This is the beginning of the real test code. The above defines + (among other things) the function rfc3484_sort. */ +Index: glibc-2.33/sunrpc/netname.c +=================================================================== +--- glibc-2.33.orig/sunrpc/netname.c ++++ glibc-2.33/sunrpc/netname.c +@@ -145,7 +145,9 @@ int + netname2user (const char *netname, uid_t * uidp, gid_t * gidp, + int *gidlenp, gid_t * gidlist) + { +- nss_action_list nip; ++ static service_user *startp; ++ static netname2user_function start_fct; ++ service_user *nip; + union + { + netname2user_function f; +@@ -154,7 +156,22 @@ netname2user (const char *netname, uid_t + enum nss_status status = NSS_STATUS_UNAVAIL; + int no_more; + +- no_more = __nss_publickey_lookup2 (&nip, "netname2user", NULL, &fct.ptr); ++ 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; ++ } + + while (!no_more) + { +Index: glibc-2.33/sunrpc/publickey.c +=================================================================== +--- glibc-2.33.orig/sunrpc/publickey.c ++++ glibc-2.33/sunrpc/publickey.c +@@ -34,7 +34,9 @@ typedef int (*secret_function) (const ch + int + getpublickey (const char *name, char *key) + { +- nss_action_list nip; ++ static service_user *startp; ++ static public_function start_fct; ++ service_user *nip; + union + { + public_function f; +@@ -43,7 +45,22 @@ getpublickey (const char *name, char *ke + enum nss_status status = NSS_STATUS_UNAVAIL; + int no_more; + +- no_more = __nss_publickey_lookup2 (&nip, "getpublickey", NULL, &fct.ptr); ++ 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; ++ } + + while (! no_more) + { +@@ -60,7 +77,9 @@ libc_hidden_nolink_sunrpc (getpublickey, + int + getsecretkey (const char *name, char *key, const char *passwd) + { +- nss_action_list nip; ++ static service_user *startp; ++ static secret_function start_fct; ++ service_user *nip; + union + { + secret_function f; +@@ -69,7 +88,22 @@ getsecretkey (const char *name, char *ke + enum nss_status status = NSS_STATUS_UNAVAIL; + int no_more; + +- no_more = __nss_publickey_lookup2 (&nip, "getsecretkey", NULL, &fct.ptr); ++ 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; ++ } + + while (! no_more) + { +Index: glibc-2.33/sysdeps/mach/hurd/fork.c +=================================================================== +--- glibc-2.33.orig/sysdeps/mach/hurd/fork.c ++++ glibc-2.33/sysdeps/mach/hurd/fork.c +@@ -28,7 +28,6 @@ + #include "hurdmalloc.h" /* XXX */ + #include + #include +-#include + + #undef __fork + +@@ -69,7 +68,6 @@ __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, ()); + +@@ -111,9 +109,6 @@ __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; +@@ -671,9 +666,6 @@ __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, ()); + +Index: glibc-2.33/sysdeps/nptl/fork.c +=================================================================== +--- glibc-2.33.orig/sysdeps/nptl/fork.c ++++ glibc-2.33/sysdeps/nptl/fork.c +@@ -32,7 +32,6 @@ + #include + #include + #include +-#include + + static void + fresetlockfiles (void) +@@ -58,8 +57,6 @@ __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 +@@ -67,9 +64,6 @@ __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 +@@ -124,9 +118,6 @@ __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. */ +Index: glibc-2.33/sysdeps/posix/getaddrinfo.c +=================================================================== +--- glibc-2.33.orig/sysdeps/posix/getaddrinfo.c ++++ glibc-2.33/sysdeps/posix/getaddrinfo.c +@@ -307,7 +307,7 @@ convert_hostent_to_gaih_addrtuple (const + memory allocation failure. The returned string is allocated on the + heap; the caller has to free it. */ + static char * +-getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name) ++getcanonname (service_user *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 struc + struct gaih_addrtuple **pat = &at; + int no_data = 0; + int no_inet6_data = 0; +- nss_action_list nip; ++ service_user *nip; + enum nss_status inet6_status = NSS_STATUS_UNAVAIL; + enum nss_status status = NSS_STATUS_UNAVAIL; + int no_more; +@@ -720,9 +720,13 @@ gaih_inet (const char *name, const struc + } + #endif + +- no_more = __nss_database_lookup2 ("hosts", NULL, +- "dns [!UNAVAIL=return] files", +- &nip); ++ if (__nss_hosts_database == NULL) ++ no_more = __nss_database_lookup2 ("hosts", NULL, ++ "dns [!UNAVAIL=return] files", ++ &__nss_hosts_database); ++ else ++ no_more = 0; ++ nip = __nss_hosts_database; + + /* If we are looking for both IPv4 and IPv6 address we don't + want the lookup functions to automatically promote IPv4 +@@ -901,9 +905,10 @@ gaih_inet (const char *name, const struc + if (nss_next_action (nip, status) == NSS_ACTION_RETURN) + break; + +- nip++; +- if (nip->module == NULL) ++ if (nip->next == NULL) + no_more = -1; ++ else ++ nip = nip->next; + } + + __resolv_context_put (res_ctx);