[7/7] nss: Access nss_files through direct references

Message ID a11b3386cbab6622b6a19fda20090c8ab5fd3a7b.1624961355.git.fweimer@redhat.com
State Committed
Commit f9c8b11ed7726b858cd7b7cea0d3d7c5233d78cf
Delegated to: Adhemerval Zanella Netto
Headers
Series nss_files move |

Checks

Context Check Description
dj/TryBot-apply_patch success Patch applied to master at the time it was sent
dj/TryBot-32bit success Build for i686

Commit Message

Florian Weimer June 29, 2021, 10:11 a.m. UTC
  This partially fixes static-only NSS support (bug 27959): The files
module no longer needs dlopen.  Support for the dns module remains
to be added, and also support for disabling dlopen altogher.
---
 include/nss_files.h              | 10 ++++++++
 nss/Makefile                     |  3 ++-
 nss/nss_files/files-XXX.c        |  6 ++++-
 nss/nss_files/files-alias.c      |  7 +++---
 nss/nss_files/files-ethers.c     |  2 --
 nss/nss_files/files-grp.c        |  2 --
 nss/nss_files/files-hosts.c      |  6 +++--
 nss/nss_files/files-init.c       |  4 +--
 nss/nss_files/files-initgroups.c |  3 +--
 nss/nss_files/files-netgrp.c     |  5 ++--
 nss/nss_files/files-network.c    |  1 -
 nss/nss_files/files-proto.c      |  2 --
 nss/nss_files/files-pwd.c        |  2 --
 nss/nss_files/files-rpc.c        |  2 --
 nss/nss_files/files-service.c    |  2 --
 nss/nss_files/files-sgrp.c       |  2 --
 nss/nss_files/files-spwd.c       |  2 --
 nss/nss_files_functions.c        | 43 ++++++++++++++++++++++++++++++++
 nss/nss_module.c                 | 38 +++++++++++++++++++++++++++-
 nss/nss_module.h                 |  4 +++
 20 files changed, 114 insertions(+), 32 deletions(-)
 create mode 100644 nss/nss_files_functions.c
  

Comments

Adhemerval Zanella Netto July 7, 2021, 1:49 p.m. UTC | #1
On 29/06/2021 07:11, Florian Weimer via Libc-alpha wrote:
> This partially fixes static-only NSS support (bug 27959): The files
> module no longer needs dlopen.  Support for the dns module remains
> to be added, and also support for disabling dlopen altogher.

s/altogher/altogether

LGTM, only a minor nit below.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org> 

> ---
>  include/nss_files.h              | 10 ++++++++
>  nss/Makefile                     |  3 ++-
>  nss/nss_files/files-XXX.c        |  6 ++++-
>  nss/nss_files/files-alias.c      |  7 +++---
>  nss/nss_files/files-ethers.c     |  2 --
>  nss/nss_files/files-grp.c        |  2 --
>  nss/nss_files/files-hosts.c      |  6 +++--
>  nss/nss_files/files-init.c       |  4 +--
>  nss/nss_files/files-initgroups.c |  3 +--
>  nss/nss_files/files-netgrp.c     |  5 ++--
>  nss/nss_files/files-network.c    |  1 -
>  nss/nss_files/files-proto.c      |  2 --
>  nss/nss_files/files-pwd.c        |  2 --
>  nss/nss_files/files-rpc.c        |  2 --
>  nss/nss_files/files-service.c    |  2 --
>  nss/nss_files/files-sgrp.c       |  2 --
>  nss/nss_files/files-spwd.c       |  2 --
>  nss/nss_files_functions.c        | 43 ++++++++++++++++++++++++++++++++
>  nss/nss_module.c                 | 38 +++++++++++++++++++++++++++-
>  nss/nss_module.h                 |  4 +++
>  20 files changed, 114 insertions(+), 32 deletions(-)
>  create mode 100644 nss/nss_files_functions.c
> 
> diff --git a/include/nss_files.h b/include/nss_files.h
> index dd0081a0f1..6190cac6be 100644
> --- a/include/nss_files.h
> +++ b/include/nss_files.h
> @@ -19,6 +19,7 @@
>  #ifndef _NSS_FILES_H
>  #define _NSS_FILES_H
>  
> +#include <nss.h>
>  #include <stdio.h>
>  #if IS_IN (libc)
>  #include <libc-lock.h>
> @@ -134,6 +135,15 @@ libc_hidden_proto (_nss_files_parse_servent)
>  libc_hidden_proto (_nss_files_parse_sgent)
>  libc_hidden_proto (_nss_files_parse_spent)
>  
> +NSS_DECLARE_MODULE_FUNCTIONS (files)
> +#undef DEFINE_NSS_FUNCTION
> +#define DEFINE_NSS_FUNCTION(x) libc_hidden_proto (_nss_files_##x)
> +#include <nss/function.def>
> +#undef DEFINE_NSS_FUNCTION
> +
> +void _nss_files_init (void (*cb) (size_t, struct traced_file *));
> +libc_hidden_proto (_nss_files_init)
> +
>  /* Generic implementation of fget*ent_r.  Reads lines from FP until
>     EOF or a successful parse into *RESULT using PARSER.  Returns 0 on
>     success, ENOENT on EOF, ERANGE on too-small buffer.  */

Ok.

> diff --git a/nss/Makefile b/nss/Makefile
> index 8905a5fd9b..75afb22cb3 100644
> --- a/nss/Makefile
> +++ b/nss/Makefile
> @@ -31,7 +31,8 @@ routines		= nsswitch getnssent getnssent_r digits_dots \
>  			  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_files_data
> +			  nss_action_parse nss_database nss_files_data \
> +			  nss_files_functions
>  
>  # These are the databases that go through nss dispatch.
>  # Caution: if you add a database here, you must add its real name

Maybe add one entry per line here?

> diff --git a/nss/nss_files/files-XXX.c b/nss/nss_files/files-XXX.c
> index 91553d7ca5..c158a891bd 100644
> --- a/nss/nss_files/files-XXX.c
> +++ b/nss/nss_files/files-XXX.c
> @@ -91,12 +91,14 @@ CONCAT(_nss_files_set,ENTNAME) (int stayopen)
>  {
>    return __nss_files_data_setent (CONCAT (nss_file_, ENTNAME), DATAFILE);
>  }
> +libc_hidden_def (CONCAT (_nss_files_set,ENTNAME))
>  
>  enum nss_status
>  CONCAT(_nss_files_end,ENTNAME) (void)
>  {
>    return __nss_files_data_endent (CONCAT (nss_file_, ENTNAME));
>  }
> +libc_hidden_def (CONCAT (_nss_files_end,ENTNAME))
>  
>  
>  /* Parsing the database file into `struct STRUCTURE' data structures.  */
> @@ -179,6 +181,7 @@ CONCAT(_nss_files_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer,
>    __nss_files_data_put (data);
>    return status;
>  }
> +libc_hidden_def (CONCAT (_nss_files_get,ENTNAME_r))
>  
>  /* Macro for defining lookup functions for this file-based database.
>  
> @@ -215,4 +218,5 @@ _nss_files_get##name##_r (proto,					      \
>      }									      \
>  									      \
>    return status;							      \
> -}
> +}									      \
> +libc_hidden_def (_nss_files_get##name##_r)

Ok.

> diff --git a/nss/nss_files/files-alias.c b/nss/nss_files/files-alias.c
> index 75d91e0b0a..8c6e176ff6 100644
> --- a/nss/nss_files/files-alias.c
> +++ b/nss/nss_files/files-alias.c
> @@ -31,8 +31,6 @@
>  #include "nsswitch.h"
>  #include <nss_files.h>
>  
> -NSS_DECLARE_MODULE_FUNCTIONS (files)
> -
>  
>  /* Maintenance of the stream open on the database file.  For getXXent
>     operations the stream needs to be held open across calls, the other
> @@ -63,12 +61,14 @@ _nss_files_setaliasent (void)
>  {
>    return __nss_files_data_setent (nss_file_aliasent, "/etc/aliases");
>  }
> +libc_hidden_def (_nss_files_setaliasent)
>  
>  enum nss_status
>  _nss_files_endaliasent (void)
>  {
>    return __nss_files_data_endent (nss_file_aliasent);
>  }
> +libc_hidden_def (_nss_files_endaliasent)
>  
>  /* Parsing the database file into `struct aliasent' data structures.  */
>  static enum nss_status
> @@ -354,7 +354,7 @@ _nss_files_getaliasent_r (struct aliasent *result, char *buffer, size_t buflen,
>    __nss_files_data_put (data);
>    return status;
>  }
> -
> +libc_hidden_def (_nss_files_getaliasent_r)
>  
>  enum nss_status
>  _nss_files_getaliasbyname_r (const char *name, struct aliasent *result,
> @@ -387,3 +387,4 @@ _nss_files_getaliasbyname_r (const char *name, struct aliasent *result,
>  
>    return status;
>  }
> +libc_hidden_def (_nss_files_getaliasbyname_r)

Ok.

> diff --git a/nss/nss_files/files-ethers.c b/nss/nss_files/files-ethers.c
> index 2fe7f81e4b..7c2c2b9833 100644
> --- a/nss/nss_files/files-ethers.c
> +++ b/nss/nss_files/files-ethers.c
> @@ -20,8 +20,6 @@
>  #include <netinet/if_ether.h>
>  #include <nss.h>
>  
> -NSS_DECLARE_MODULE_FUNCTIONS (files)
> -
>  struct etherent_data {};
>  
>  #define ENTNAME		etherent

Ok.

> diff --git a/nss/nss_files/files-grp.c b/nss/nss_files/files-grp.c
> index 49be38e8b1..a716d948e2 100644
> --- a/nss/nss_files/files-grp.c
> +++ b/nss/nss_files/files-grp.c
> @@ -19,8 +19,6 @@
>  #include <grp.h>
>  #include <nss.h>
>  
> -NSS_DECLARE_MODULE_FUNCTIONS (files)
> -
>  #define STRUCTURE	group
>  #define ENTNAME		grent
>  #define DATABASE	"group"

Ok.

> diff --git a/nss/nss_files/files-hosts.c b/nss/nss_files/files-hosts.c
> index 894b85d501..d54d91d038 100644
> --- a/nss/nss_files/files-hosts.c
> +++ b/nss/nss_files/files-hosts.c
> @@ -26,8 +26,6 @@
>  #include <alloc_buffer.h>
>  #include <nss.h>
>  
> -NSS_DECLARE_MODULE_FUNCTIONS (files)
> -
>  /* Get implementation for some internal functions.  */
>  #include "../resolv/res_hconf.h"
>  
> @@ -358,6 +356,7 @@ _nss_files_gethostbyname3_r (const char *name, int af, struct hostent *result,
>  
>    return status;
>  }
> +libc_hidden_def (_nss_files_gethostbyname3_r)
>  
>  enum nss_status
>  _nss_files_gethostbyname_r (const char *name, struct hostent *result,
> @@ -367,6 +366,7 @@ _nss_files_gethostbyname_r (const char *name, struct hostent *result,
>    return _nss_files_gethostbyname3_r (name, AF_INET, result, buffer, buflen,
>  				      errnop, herrnop, NULL, NULL);
>  }
> +libc_hidden_def (_nss_files_gethostbyname_r)
>  
>  enum nss_status
>  _nss_files_gethostbyname2_r (const char *name, int af, struct hostent *result,
> @@ -376,6 +376,7 @@ _nss_files_gethostbyname2_r (const char *name, int af, struct hostent *result,
>    return _nss_files_gethostbyname3_r (name, af, result, buffer, buflen,
>  				      errnop, herrnop, NULL, NULL);
>  }
> +libc_hidden_def (_nss_files_gethostbyname2_r)
>  
>  enum nss_status
>  _nss_files_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
> @@ -491,3 +492,4 @@ _nss_files_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
>  
>    return status;
>  }
> +libc_hidden_def (_nss_files_gethostbyname4_r)

Ok.

> diff --git a/nss/nss_files/files-init.c b/nss/nss_files/files-init.c
> index 36d5ebce1f..18d48168e8 100644
> --- a/nss/nss_files/files-init.c
> +++ b/nss/nss_files/files-init.c
> @@ -21,8 +21,7 @@
>  #include <string.h>
>  #include <nscd/nscd.h>
>  #include <nss.h>
> -
> -NSS_DECLARE_MODULE_FUNCTIONS (files)
> +#include <nss_files.h>
>  
>  static void
>  register_file (void (*cb) (size_t, struct traced_file *),
> @@ -49,5 +48,6 @@ _nss_files_init (void (*cb) (size_t, struct traced_file *))
>    register_file (cb, servdb, "/etc/services", 0);
>    register_file (cb, netgrdb, "/etc/netgroup", 0);
>  }
> +libc_hidden_def (_nss_files_init)
>  
>  #endif

Ok.

> diff --git a/nss/nss_files/files-initgroups.c b/nss/nss_files/files-initgroups.c
> index 6fcea40b55..b44211e50b 100644
> --- a/nss/nss_files/files-initgroups.c
> +++ b/nss/nss_files/files-initgroups.c
> @@ -28,8 +28,6 @@
>  #include <nss.h>
>  #include <nss_files.h>
>  
> -NSS_DECLARE_MODULE_FUNCTIONS (files)
> -
>  enum nss_status
>  _nss_files_initgroups_dyn (const char *user, gid_t group, long int *start,
>  			   long int *size, gid_t **groupsp, long int limit,
> @@ -129,3 +127,4 @@ _nss_files_initgroups_dyn (const char *user, gid_t group, long int *start,
>  
>    return status == NSS_STATUS_SUCCESS && !any ? NSS_STATUS_NOTFOUND : status;
>  }
> +libc_hidden_def (_nss_files_initgroups_dyn)

Ok.

> diff --git a/nss/nss_files/files-netgrp.c b/nss/nss_files/files-netgrp.c
> index be9c72accf..75bfbd9e44 100644
> --- a/nss/nss_files/files-netgrp.c
> +++ b/nss/nss_files/files-netgrp.c
> @@ -28,8 +28,6 @@
>  #include "netgroup.h"
>  #include <nss_files.h>
>  
> -NSS_DECLARE_MODULE_FUNCTIONS (files)
> -
>  #define DATAFILE	"/etc/netgroup"
>  
>  libc_hidden_proto (_nss_files_endnetgrent)
> @@ -152,7 +150,7 @@ _nss_files_setnetgrent (const char *group, struct __netgrent *result)
>  
>    return status;
>  }
> -
> +libc_hidden_def (_nss_files_setnetgrent)
>  
>  enum nss_status
>  _nss_files_endnetgrent (struct __netgrent *result)
> @@ -293,3 +291,4 @@ _nss_files_getnetgrent_r (struct __netgrent *result, char *buffer,
>  
>    return status;
>  }
> +libc_hidden_def (_nss_files_getnetgrent_r)

Ok.

> diff --git a/nss/nss_files/files-network.c b/nss/nss_files/files-network.c
> index 75c9f8a57e..217ed78609 100644
> --- a/nss/nss_files/files-network.c
> +++ b/nss/nss_files/files-network.c
> @@ -21,7 +21,6 @@
>  #include <netdb.h>
>  #include <stdint.h>
>  #include <nss.h>
> -#include <nss_files.h>
>  
>  #define ENTNAME		netent
>  #define DATABASE	"networks"

Ok.

> diff --git a/nss/nss_files/files-proto.c b/nss/nss_files/files-proto.c
> index 98d082c642..13072692c1 100644
> --- a/nss/nss_files/files-proto.c
> +++ b/nss/nss_files/files-proto.c
> @@ -19,8 +19,6 @@
>  #include <netdb.h>
>  #include <nss.h>
>  
> -NSS_DECLARE_MODULE_FUNCTIONS (files)
> -
>  #define ENTNAME		protoent
>  #define DATABASE	"protocols"
>  

Ok.

> diff --git a/nss/nss_files/files-pwd.c b/nss/nss_files/files-pwd.c
> index b04165ddde..5c74c6da9b 100644
> --- a/nss/nss_files/files-pwd.c
> +++ b/nss/nss_files/files-pwd.c
> @@ -19,8 +19,6 @@
>  #include <pwd.h>
>  #include <nss.h>
>  
> -NSS_DECLARE_MODULE_FUNCTIONS (files)
> -
>  #define STRUCTURE	passwd
>  #define ENTNAME		pwent
>  #define DATABASE	"passwd"

Ok.

> diff --git a/nss/nss_files/files-rpc.c b/nss/nss_files/files-rpc.c
> index eeb2725d2c..3dea8f18f2 100644
> --- a/nss/nss_files/files-rpc.c
> +++ b/nss/nss_files/files-rpc.c
> @@ -19,8 +19,6 @@
>  #include <rpc/netdb.h>
>  #include <nss.h>
>  
> -NSS_DECLARE_MODULE_FUNCTIONS (files)
> -
>  #define ENTNAME		rpcent
>  #define DATABASE	"rpc"
>  

Ok.

> diff --git a/nss/nss_files/files-service.c b/nss/nss_files/files-service.c
> index f4f0985377..a8d83e094e 100644
> --- a/nss/nss_files/files-service.c
> +++ b/nss/nss_files/files-service.c
> @@ -20,8 +20,6 @@
>  #include <netdb.h>
>  #include <nss.h>
>  
> -NSS_DECLARE_MODULE_FUNCTIONS (files)
> -
>  #define ENTNAME		servent
>  #define DATABASE	"services"
>  

Ok.

> diff --git a/nss/nss_files/files-sgrp.c b/nss/nss_files/files-sgrp.c
> index 6b1c9eac02..213a408e7b 100644
> --- a/nss/nss_files/files-sgrp.c
> +++ b/nss/nss_files/files-sgrp.c
> @@ -19,8 +19,6 @@
>  #include <gshadow.h>
>  #include <nss.h>
>  
> -NSS_DECLARE_MODULE_FUNCTIONS (files)
> -
>  #define STRUCTURE	sgrp
>  #define ENTNAME		sgent
>  #define DATABASE	"gshadow"
> diff --git a/nss/nss_files/files-spwd.c b/nss/nss_files/files-spwd.c
> index 976deaf918..d031257a20 100644
> --- a/nss/nss_files/files-spwd.c
> +++ b/nss/nss_files/files-spwd.c
> @@ -19,8 +19,6 @@
>  #include <shadow.h>
>  #include <nss.h>
>  
> -NSS_DECLARE_MODULE_FUNCTIONS (files)
> -
>  #define STRUCTURE	spwd
>  #define ENTNAME		spent
>  #define DATABASE	"shadow"

Ok.

> diff --git a/nss/nss_files_functions.c b/nss/nss_files_functions.c
> new file mode 100644
> index 0000000000..85720b4311
> --- /dev/null
> +++ b/nss/nss_files_functions.c
> @@ -0,0 +1,43 @@
> +/* Direct access for nss_files functions for NSS module loading.
> +   Copyright (C) 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
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <nss_module.h>
> +#include <nss_files.h>
> +
> +void
> +__nss_files_functions (nss_module_functions_untyped pointers)
> +{
> +  void **fptr = pointers;
> +
> +  /* Functions which are not implemented.  */
> +#define _nss_files_getcanonname_r NULL
> +#define _nss_files_gethostbyaddr2_r NULL
> +#define _nss_files_getpublickey NULL
> +#define _nss_files_getsecretkey NULL
> +#define _nss_files_netname2user NULL
> +
> +#undef DEFINE_NSS_FUNCTION
> +#define DEFINE_NSS_FUNCTION(x) *fptr++ = _nss_files_##x;
> +#include "function.def"
> +
> +#ifdef PTR_MANGLE
> +  void **end = fptr;
> +  for (fptr = pointers; fptr != end; ++fptr)
> +    PTR_MANGLE (*fptr);
> +#endif
> +}

Ok.

> diff --git a/nss/nss_module.c b/nss/nss_module.c
> index 60c070c851..7b42c585a4 100644
> --- a/nss/nss_module.c
> +++ b/nss/nss_module.c
> @@ -30,6 +30,7 @@
>  #include <stdio.h>
>  #include <stdlib.h>
>  #include <string.h>
> +#include <nss_files.h>
>  
>  /* 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
> @@ -110,10 +111,45 @@ static const function_name nss_function_name_array[] =
>  #include "function.def"
>    };
>  
> +static bool
> +module_load_nss_files (struct nss_module *module)
> +{
> +  if (is_nscd)
> +    {
> +      void (*cb) (size_t, struct traced_file *) = nscd_init_cb;
> +#  ifdef PTR_DEMANGLE
> +      PTR_DEMANGLE (cb);
> +#  endif
> +      _nss_files_init (cb);
> +    }
> +
> +  /* Initialize the function pointers, following the double-checked
> +     locking idiom.  */
> +  __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:
> +      __nss_files_functions (module->functions.untyped);
> +      module->handle = NULL;
> +      /* Synchronizes with unlocked __nss_module_load atomic_load_acquire.  */
> +      atomic_store_release (&module->state, nss_module_loaded);
> +      break;
> +    case nss_module_loaded:
> +      /* Nothing to clean up.  */
> +      break;
> +    }
> +  __libc_lock_unlock (nss_module_list_lock);
> +  return true;
> +}
> +

Ok (it is mainly the code already presented on module_load()).

>  /* Internal implementation of __nss_module_load.  */
>  static bool
>  module_load (struct nss_module *module)
>  {
> +  if (strcmp (module->name, "files") == 0)
> +    return module_load_nss_files (module);
> +
>    void *handle;
>    {
>      char *shlib_name;
> @@ -360,7 +396,7 @@ __nss_module_freeres (void)
>    struct nss_module *current = nss_module_list;
>    while (current != NULL)
>      {
> -      if (current->state == nss_module_loaded)
> +      if (current->state == nss_module_loaded && current->handle != NULL)
>          __libc_dlclose (current->handle);
>  
>        struct nss_module *next = current->next;

Ok.

> diff --git a/nss/nss_module.h b/nss/nss_module.h
> index 05c4791d11..c1a1d90b60 100644
> --- a/nss/nss_module.h
> +++ b/nss/nss_module.h
> @@ -38,6 +38,10 @@ struct nss_module_functions
>  typedef void *nss_module_functions_untyped[sizeof (struct nss_module_functions)
>                                             / sizeof (void *)];
>  
> +/* Locate the nss_files functions, as if by dlopen/dlsym.  */
> +void __nss_files_functions (nss_module_functions_untyped pointers)
> +  attribute_hidden;
> +
>  /* Initialization state of a NSS module.  */
>  enum nss_module_state
>  {
> 

Ok.
  

Patch

diff --git a/include/nss_files.h b/include/nss_files.h
index dd0081a0f1..6190cac6be 100644
--- a/include/nss_files.h
+++ b/include/nss_files.h
@@ -19,6 +19,7 @@ 
 #ifndef _NSS_FILES_H
 #define _NSS_FILES_H
 
+#include <nss.h>
 #include <stdio.h>
 #if IS_IN (libc)
 #include <libc-lock.h>
@@ -134,6 +135,15 @@  libc_hidden_proto (_nss_files_parse_servent)
 libc_hidden_proto (_nss_files_parse_sgent)
 libc_hidden_proto (_nss_files_parse_spent)
 
+NSS_DECLARE_MODULE_FUNCTIONS (files)
+#undef DEFINE_NSS_FUNCTION
+#define DEFINE_NSS_FUNCTION(x) libc_hidden_proto (_nss_files_##x)
+#include <nss/function.def>
+#undef DEFINE_NSS_FUNCTION
+
+void _nss_files_init (void (*cb) (size_t, struct traced_file *));
+libc_hidden_proto (_nss_files_init)
+
 /* Generic implementation of fget*ent_r.  Reads lines from FP until
    EOF or a successful parse into *RESULT using PARSER.  Returns 0 on
    success, ENOENT on EOF, ERANGE on too-small buffer.  */
diff --git a/nss/Makefile b/nss/Makefile
index 8905a5fd9b..75afb22cb3 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -31,7 +31,8 @@  routines		= nsswitch getnssent getnssent_r digits_dots \
 			  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_files_data
+			  nss_action_parse nss_database nss_files_data \
+			  nss_files_functions
 
 # These are the databases that go through nss dispatch.
 # Caution: if you add a database here, you must add its real name
diff --git a/nss/nss_files/files-XXX.c b/nss/nss_files/files-XXX.c
index 91553d7ca5..c158a891bd 100644
--- a/nss/nss_files/files-XXX.c
+++ b/nss/nss_files/files-XXX.c
@@ -91,12 +91,14 @@  CONCAT(_nss_files_set,ENTNAME) (int stayopen)
 {
   return __nss_files_data_setent (CONCAT (nss_file_, ENTNAME), DATAFILE);
 }
+libc_hidden_def (CONCAT (_nss_files_set,ENTNAME))
 
 enum nss_status
 CONCAT(_nss_files_end,ENTNAME) (void)
 {
   return __nss_files_data_endent (CONCAT (nss_file_, ENTNAME));
 }
+libc_hidden_def (CONCAT (_nss_files_end,ENTNAME))
 
 
 /* Parsing the database file into `struct STRUCTURE' data structures.  */
@@ -179,6 +181,7 @@  CONCAT(_nss_files_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer,
   __nss_files_data_put (data);
   return status;
 }
+libc_hidden_def (CONCAT (_nss_files_get,ENTNAME_r))
 
 /* Macro for defining lookup functions for this file-based database.
 
@@ -215,4 +218,5 @@  _nss_files_get##name##_r (proto,					      \
     }									      \
 									      \
   return status;							      \
-}
+}									      \
+libc_hidden_def (_nss_files_get##name##_r)
diff --git a/nss/nss_files/files-alias.c b/nss/nss_files/files-alias.c
index 75d91e0b0a..8c6e176ff6 100644
--- a/nss/nss_files/files-alias.c
+++ b/nss/nss_files/files-alias.c
@@ -31,8 +31,6 @@ 
 #include "nsswitch.h"
 #include <nss_files.h>
 
-NSS_DECLARE_MODULE_FUNCTIONS (files)
-
 
 /* Maintenance of the stream open on the database file.  For getXXent
    operations the stream needs to be held open across calls, the other
@@ -63,12 +61,14 @@  _nss_files_setaliasent (void)
 {
   return __nss_files_data_setent (nss_file_aliasent, "/etc/aliases");
 }
+libc_hidden_def (_nss_files_setaliasent)
 
 enum nss_status
 _nss_files_endaliasent (void)
 {
   return __nss_files_data_endent (nss_file_aliasent);
 }
+libc_hidden_def (_nss_files_endaliasent)
 
 /* Parsing the database file into `struct aliasent' data structures.  */
 static enum nss_status
@@ -354,7 +354,7 @@  _nss_files_getaliasent_r (struct aliasent *result, char *buffer, size_t buflen,
   __nss_files_data_put (data);
   return status;
 }
-
+libc_hidden_def (_nss_files_getaliasent_r)
 
 enum nss_status
 _nss_files_getaliasbyname_r (const char *name, struct aliasent *result,
@@ -387,3 +387,4 @@  _nss_files_getaliasbyname_r (const char *name, struct aliasent *result,
 
   return status;
 }
+libc_hidden_def (_nss_files_getaliasbyname_r)
diff --git a/nss/nss_files/files-ethers.c b/nss/nss_files/files-ethers.c
index 2fe7f81e4b..7c2c2b9833 100644
--- a/nss/nss_files/files-ethers.c
+++ b/nss/nss_files/files-ethers.c
@@ -20,8 +20,6 @@ 
 #include <netinet/if_ether.h>
 #include <nss.h>
 
-NSS_DECLARE_MODULE_FUNCTIONS (files)
-
 struct etherent_data {};
 
 #define ENTNAME		etherent
diff --git a/nss/nss_files/files-grp.c b/nss/nss_files/files-grp.c
index 49be38e8b1..a716d948e2 100644
--- a/nss/nss_files/files-grp.c
+++ b/nss/nss_files/files-grp.c
@@ -19,8 +19,6 @@ 
 #include <grp.h>
 #include <nss.h>
 
-NSS_DECLARE_MODULE_FUNCTIONS (files)
-
 #define STRUCTURE	group
 #define ENTNAME		grent
 #define DATABASE	"group"
diff --git a/nss/nss_files/files-hosts.c b/nss/nss_files/files-hosts.c
index 894b85d501..d54d91d038 100644
--- a/nss/nss_files/files-hosts.c
+++ b/nss/nss_files/files-hosts.c
@@ -26,8 +26,6 @@ 
 #include <alloc_buffer.h>
 #include <nss.h>
 
-NSS_DECLARE_MODULE_FUNCTIONS (files)
-
 /* Get implementation for some internal functions.  */
 #include "../resolv/res_hconf.h"
 
@@ -358,6 +356,7 @@  _nss_files_gethostbyname3_r (const char *name, int af, struct hostent *result,
 
   return status;
 }
+libc_hidden_def (_nss_files_gethostbyname3_r)
 
 enum nss_status
 _nss_files_gethostbyname_r (const char *name, struct hostent *result,
@@ -367,6 +366,7 @@  _nss_files_gethostbyname_r (const char *name, struct hostent *result,
   return _nss_files_gethostbyname3_r (name, AF_INET, result, buffer, buflen,
 				      errnop, herrnop, NULL, NULL);
 }
+libc_hidden_def (_nss_files_gethostbyname_r)
 
 enum nss_status
 _nss_files_gethostbyname2_r (const char *name, int af, struct hostent *result,
@@ -376,6 +376,7 @@  _nss_files_gethostbyname2_r (const char *name, int af, struct hostent *result,
   return _nss_files_gethostbyname3_r (name, af, result, buffer, buflen,
 				      errnop, herrnop, NULL, NULL);
 }
+libc_hidden_def (_nss_files_gethostbyname2_r)
 
 enum nss_status
 _nss_files_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
@@ -491,3 +492,4 @@  _nss_files_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
 
   return status;
 }
+libc_hidden_def (_nss_files_gethostbyname4_r)
diff --git a/nss/nss_files/files-init.c b/nss/nss_files/files-init.c
index 36d5ebce1f..18d48168e8 100644
--- a/nss/nss_files/files-init.c
+++ b/nss/nss_files/files-init.c
@@ -21,8 +21,7 @@ 
 #include <string.h>
 #include <nscd/nscd.h>
 #include <nss.h>
-
-NSS_DECLARE_MODULE_FUNCTIONS (files)
+#include <nss_files.h>
 
 static void
 register_file (void (*cb) (size_t, struct traced_file *),
@@ -49,5 +48,6 @@  _nss_files_init (void (*cb) (size_t, struct traced_file *))
   register_file (cb, servdb, "/etc/services", 0);
   register_file (cb, netgrdb, "/etc/netgroup", 0);
 }
+libc_hidden_def (_nss_files_init)
 
 #endif
diff --git a/nss/nss_files/files-initgroups.c b/nss/nss_files/files-initgroups.c
index 6fcea40b55..b44211e50b 100644
--- a/nss/nss_files/files-initgroups.c
+++ b/nss/nss_files/files-initgroups.c
@@ -28,8 +28,6 @@ 
 #include <nss.h>
 #include <nss_files.h>
 
-NSS_DECLARE_MODULE_FUNCTIONS (files)
-
 enum nss_status
 _nss_files_initgroups_dyn (const char *user, gid_t group, long int *start,
 			   long int *size, gid_t **groupsp, long int limit,
@@ -129,3 +127,4 @@  _nss_files_initgroups_dyn (const char *user, gid_t group, long int *start,
 
   return status == NSS_STATUS_SUCCESS && !any ? NSS_STATUS_NOTFOUND : status;
 }
+libc_hidden_def (_nss_files_initgroups_dyn)
diff --git a/nss/nss_files/files-netgrp.c b/nss/nss_files/files-netgrp.c
index be9c72accf..75bfbd9e44 100644
--- a/nss/nss_files/files-netgrp.c
+++ b/nss/nss_files/files-netgrp.c
@@ -28,8 +28,6 @@ 
 #include "netgroup.h"
 #include <nss_files.h>
 
-NSS_DECLARE_MODULE_FUNCTIONS (files)
-
 #define DATAFILE	"/etc/netgroup"
 
 libc_hidden_proto (_nss_files_endnetgrent)
@@ -152,7 +150,7 @@  _nss_files_setnetgrent (const char *group, struct __netgrent *result)
 
   return status;
 }
-
+libc_hidden_def (_nss_files_setnetgrent)
 
 enum nss_status
 _nss_files_endnetgrent (struct __netgrent *result)
@@ -293,3 +291,4 @@  _nss_files_getnetgrent_r (struct __netgrent *result, char *buffer,
 
   return status;
 }
+libc_hidden_def (_nss_files_getnetgrent_r)
diff --git a/nss/nss_files/files-network.c b/nss/nss_files/files-network.c
index 75c9f8a57e..217ed78609 100644
--- a/nss/nss_files/files-network.c
+++ b/nss/nss_files/files-network.c
@@ -21,7 +21,6 @@ 
 #include <netdb.h>
 #include <stdint.h>
 #include <nss.h>
-#include <nss_files.h>
 
 #define ENTNAME		netent
 #define DATABASE	"networks"
diff --git a/nss/nss_files/files-proto.c b/nss/nss_files/files-proto.c
index 98d082c642..13072692c1 100644
--- a/nss/nss_files/files-proto.c
+++ b/nss/nss_files/files-proto.c
@@ -19,8 +19,6 @@ 
 #include <netdb.h>
 #include <nss.h>
 
-NSS_DECLARE_MODULE_FUNCTIONS (files)
-
 #define ENTNAME		protoent
 #define DATABASE	"protocols"
 
diff --git a/nss/nss_files/files-pwd.c b/nss/nss_files/files-pwd.c
index b04165ddde..5c74c6da9b 100644
--- a/nss/nss_files/files-pwd.c
+++ b/nss/nss_files/files-pwd.c
@@ -19,8 +19,6 @@ 
 #include <pwd.h>
 #include <nss.h>
 
-NSS_DECLARE_MODULE_FUNCTIONS (files)
-
 #define STRUCTURE	passwd
 #define ENTNAME		pwent
 #define DATABASE	"passwd"
diff --git a/nss/nss_files/files-rpc.c b/nss/nss_files/files-rpc.c
index eeb2725d2c..3dea8f18f2 100644
--- a/nss/nss_files/files-rpc.c
+++ b/nss/nss_files/files-rpc.c
@@ -19,8 +19,6 @@ 
 #include <rpc/netdb.h>
 #include <nss.h>
 
-NSS_DECLARE_MODULE_FUNCTIONS (files)
-
 #define ENTNAME		rpcent
 #define DATABASE	"rpc"
 
diff --git a/nss/nss_files/files-service.c b/nss/nss_files/files-service.c
index f4f0985377..a8d83e094e 100644
--- a/nss/nss_files/files-service.c
+++ b/nss/nss_files/files-service.c
@@ -20,8 +20,6 @@ 
 #include <netdb.h>
 #include <nss.h>
 
-NSS_DECLARE_MODULE_FUNCTIONS (files)
-
 #define ENTNAME		servent
 #define DATABASE	"services"
 
diff --git a/nss/nss_files/files-sgrp.c b/nss/nss_files/files-sgrp.c
index 6b1c9eac02..213a408e7b 100644
--- a/nss/nss_files/files-sgrp.c
+++ b/nss/nss_files/files-sgrp.c
@@ -19,8 +19,6 @@ 
 #include <gshadow.h>
 #include <nss.h>
 
-NSS_DECLARE_MODULE_FUNCTIONS (files)
-
 #define STRUCTURE	sgrp
 #define ENTNAME		sgent
 #define DATABASE	"gshadow"
diff --git a/nss/nss_files/files-spwd.c b/nss/nss_files/files-spwd.c
index 976deaf918..d031257a20 100644
--- a/nss/nss_files/files-spwd.c
+++ b/nss/nss_files/files-spwd.c
@@ -19,8 +19,6 @@ 
 #include <shadow.h>
 #include <nss.h>
 
-NSS_DECLARE_MODULE_FUNCTIONS (files)
-
 #define STRUCTURE	spwd
 #define ENTNAME		spent
 #define DATABASE	"shadow"
diff --git a/nss/nss_files_functions.c b/nss/nss_files_functions.c
new file mode 100644
index 0000000000..85720b4311
--- /dev/null
+++ b/nss/nss_files_functions.c
@@ -0,0 +1,43 @@ 
+/* Direct access for nss_files functions for NSS module loading.
+   Copyright (C) 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <nss_module.h>
+#include <nss_files.h>
+
+void
+__nss_files_functions (nss_module_functions_untyped pointers)
+{
+  void **fptr = pointers;
+
+  /* Functions which are not implemented.  */
+#define _nss_files_getcanonname_r NULL
+#define _nss_files_gethostbyaddr2_r NULL
+#define _nss_files_getpublickey NULL
+#define _nss_files_getsecretkey NULL
+#define _nss_files_netname2user NULL
+
+#undef DEFINE_NSS_FUNCTION
+#define DEFINE_NSS_FUNCTION(x) *fptr++ = _nss_files_##x;
+#include "function.def"
+
+#ifdef PTR_MANGLE
+  void **end = fptr;
+  for (fptr = pointers; fptr != end; ++fptr)
+    PTR_MANGLE (*fptr);
+#endif
+}
diff --git a/nss/nss_module.c b/nss/nss_module.c
index 60c070c851..7b42c585a4 100644
--- a/nss/nss_module.c
+++ b/nss/nss_module.c
@@ -30,6 +30,7 @@ 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <nss_files.h>
 
 /* 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
@@ -110,10 +111,45 @@  static const function_name nss_function_name_array[] =
 #include "function.def"
   };
 
+static bool
+module_load_nss_files (struct nss_module *module)
+{
+  if (is_nscd)
+    {
+      void (*cb) (size_t, struct traced_file *) = nscd_init_cb;
+#  ifdef PTR_DEMANGLE
+      PTR_DEMANGLE (cb);
+#  endif
+      _nss_files_init (cb);
+    }
+
+  /* Initialize the function pointers, following the double-checked
+     locking idiom.  */
+  __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:
+      __nss_files_functions (module->functions.untyped);
+      module->handle = NULL;
+      /* Synchronizes with unlocked __nss_module_load atomic_load_acquire.  */
+      atomic_store_release (&module->state, nss_module_loaded);
+      break;
+    case nss_module_loaded:
+      /* Nothing to clean up.  */
+      break;
+    }
+  __libc_lock_unlock (nss_module_list_lock);
+  return true;
+}
+
 /* Internal implementation of __nss_module_load.  */
 static bool
 module_load (struct nss_module *module)
 {
+  if (strcmp (module->name, "files") == 0)
+    return module_load_nss_files (module);
+
   void *handle;
   {
     char *shlib_name;
@@ -360,7 +396,7 @@  __nss_module_freeres (void)
   struct nss_module *current = nss_module_list;
   while (current != NULL)
     {
-      if (current->state == nss_module_loaded)
+      if (current->state == nss_module_loaded && current->handle != NULL)
         __libc_dlclose (current->handle);
 
       struct nss_module *next = current->next;
diff --git a/nss/nss_module.h b/nss/nss_module.h
index 05c4791d11..c1a1d90b60 100644
--- a/nss/nss_module.h
+++ b/nss/nss_module.h
@@ -38,6 +38,10 @@  struct nss_module_functions
 typedef void *nss_module_functions_untyped[sizeof (struct nss_module_functions)
                                            / sizeof (void *)];
 
+/* Locate the nss_files functions, as if by dlopen/dlsym.  */
+void __nss_files_functions (nss_module_functions_untyped pointers)
+  attribute_hidden;
+
 /* Initialization state of a NSS module.  */
 enum nss_module_state
 {