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);