[PATCH v2 20/23] nss: Convert passwd database to new NSS framework

Carlos O'Donell carlos@redhat.com
Tue Mar 24 21:39:07 GMT 2026


On 3/20/26 4:43 PM, Florian Weimer wrote:
> This framework moves the ERANGE down a couple of layers.  The intent
> is to migrate to an interface eventually where NSS service modules
> allocate data for the response size they need.
> 
> The need for the function-specific GLIBC_2.1.2 versioned symbol
> is rather unfortunate.  With out the existing preprocessor approach
> in nss/getXXbyYY_r.c, this adds a lot of duplicated code.  A future
> version could use compile-time code generation (outside of the
> preprocessor) to generate the _r function wrappers and the
> code for the compatibility code.  The advantage over the preprocessor
> approach is that the resulting code will still be straightforward
> to debug because line-based breakpoints work exactly as expected.

LGTM.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>

> ---
>   include/set-freeres.h     |  4 +--
>   malloc/set-freeres.c      |  7 +---
>   nscd/nscd_proto.h         |  2 ++
>   nss/Makefile              |  7 ++++
>   nss/getpwnam.c            | 14 ++++----
>   nss/getpwnam_r.c          | 33 +++++++++++++++----
>   nss/getpwuid.c            | 14 ++++----
>   nss/getpwuid_r.c          | 33 +++++++++++++++----
>   nss/nss_generic.h         | 63 ++++++++++++++++++++++++++++++++++++
>   nss/nss_generic_get.c     | 61 +++++++++++++++++++++++++++++++++++
>   nss/nss_generic_get_r.c   | 45 ++++++++++++++++++++++++++
>   nss/nss_generic_lookup.c  | 51 +++++++++++++++++++++++++++++
>   nss/nss_generic_next.c    | 60 +++++++++++++++++++++++++++++++++++
>   nss/nss_generic_storage.h | 30 ++++++++++++++++++
>   nss/nss_getX.c            | 53 +++++++++++++++++++++++++++++++
>   nss/nss_getX_r.c          | 45 ++++++++++++++++++++++++++
>   nss/nss_getXinfo.c        | 67 +++++++++++++++++++++++++++++++++++++++
>   17 files changed, 551 insertions(+), 38 deletions(-)
>   create mode 100644 nss/nss_generic_get.c
>   create mode 100644 nss/nss_generic_get_r.c
>   create mode 100644 nss/nss_generic_lookup.c
>   create mode 100644 nss/nss_generic_next.c
>   create mode 100644 nss/nss_generic_storage.h
>   create mode 100644 nss/nss_getX.c
>   create mode 100644 nss/nss_getX_r.c
>   create mode 100644 nss/nss_getXinfo.c
> 
> diff --git a/include/set-freeres.h b/include/set-freeres.h
> index 55093aa89d..c9d2c8ae55 100644
> --- a/include/set-freeres.h
> +++ b/include/set-freeres.h
> @@ -68,6 +68,8 @@ extern void __nss_module_freeres (void) attribute_hidden;
>   extern void __nss_action_freeres (void) attribute_hidden;
>   /* From nss/nss_database.c */
>   extern void __nss_database_freeres (void) attribute_hidden;
> +/* From nss/nss-generic.h.  */
> +void __nss_generic_freeres (void) attribute_hidden;
>   /* From libio/genops.c */
>   extern int _IO_cleanup (void) attribute_hidden;;
>   /* From dlfcn/dlerror.c */
> @@ -102,8 +104,6 @@ extern printf_va_arg_function ** __libc_reg_type_freemem_ptr
>   /* From nss/getXXbyYY.c  */
>   extern char * __libc_getgrgid_freemem_ptr attribute_hidden;
>   extern char * __libc_getgrnam_freemem_ptr attribute_hidden;
> -extern char * __libc_getpwnam_freemem_ptr attribute_hidden;
> -extern char * __libc_getpwuid_freemem_ptr attribute_hidden;
>   extern char * __libc_getspnam_freemem_ptr attribute_hidden;
>   extern char * __libc_getaliasbyname_freemem_ptr attribute_hidden;
>   extern char * __libc_gethostbyaddr_freemem_ptr attribute_hidden;
> diff --git a/malloc/set-freeres.c b/malloc/set-freeres.c
> index 39fd7d4d27..8112a2f664 100644
> --- a/malloc/set-freeres.c
> +++ b/malloc/set-freeres.c
> @@ -74,8 +74,6 @@
>   # pragma weak __libc_reg_type_freemem_ptr
>   # pragma weak __libc_getgrgid_freemem_ptr
>   # pragma weak __libc_getgrnam_freemem_ptr
> -# pragma weak __libc_getpwnam_freemem_ptr
> -# pragma weak __libc_getpwuid_freemem_ptr
>   # pragma weak __libc_getspnam_freemem_ptr
>   # pragma weak __libc_getaliasbyname_freemem_ptr
>   # pragma weak __libc_gethostbyaddr_freemem_ptr
> @@ -124,6 +122,7 @@ __libc_freeres (void)
>         call_function_static_weak (__nss_module_freeres);
>         call_function_static_weak (__nss_action_freeres);
>         call_function_static_weak (__nss_database_freeres);
> +      call_function_static_weak (__nss_generic_freeres);
>   
>         _IO_cleanup ();
>   
> @@ -188,10 +187,6 @@ __libc_freeres (void)
>         call_free_static_weak (__libc_reg_printf_freemem_ptr);
>         call_free_static_weak (__libc_reg_type_freemem_ptr);
>   
> -      call_free_static_weak (__libc_getgrgid_freemem_ptr);
> -      call_free_static_weak (__libc_getgrnam_freemem_ptr);
> -      call_free_static_weak (__libc_getpwnam_freemem_ptr);
> -      call_free_static_weak (__libc_getpwuid_freemem_ptr);
>         call_free_static_weak (__libc_getspnam_freemem_ptr);
>         call_free_static_weak (__libc_getaliasbyname_freemem_ptr);
>         call_free_static_weak (__libc_gethostbyaddr_freemem_ptr);
> diff --git a/nscd/nscd_proto.h b/nscd/nscd_proto.h
> index 6c4a318bc0..da3156b0ff 100644
> --- a/nscd/nscd_proto.h
> +++ b/nscd/nscd_proto.h
> @@ -42,9 +42,11 @@ void __nscd_disable_database (unsigned int db) attribute_hidden;
>   extern int __nscd_getpwnam_r (const char *name, struct passwd *resultbuf,
>   			      char *buffer, size_t buflen,
>   			      struct passwd **result) attribute_hidden;
> +int __nscd_getpwnam (const char *name, struct passwd **) attribute_hidden;
>   extern int __nscd_getpwuid_r (uid_t uid, struct passwd *resultbuf,
>   			      char *buffer,  size_t buflen,
>   			      struct passwd **result) attribute_hidden;
> +int __nscd_getpwuid (uid_t uid, struct passwd **result) attribute_hidden;
>   extern int __nscd_getgrnam_r (const char *name, struct group *resultbuf,
>   			      char *buffer, size_t buflen,
>   			      struct group **result) attribute_hidden;
> diff --git a/nss/Makefile b/nss/Makefile
> index 82f5a5d68f..a13f6fa10c 100644
> --- a/nss/Makefile
> +++ b/nss/Makefile
> @@ -47,7 +47,14 @@ routines = \
>     nss_files_functions \
>     nss_generic_copy \
>     nss_generic_dup \
> +  nss_generic_get \
> +  nss_generic_get_r \
> +  nss_generic_lookup \
> +  nss_generic_next \

OK.

>     nss_generic_nscd \
> +  nss_getX \
> +  nss_getX_r \
> +  nss_getXinfo \

OK.

>     nss_hash \
>     nss_module \
>     nss_parse_line_result \
> diff --git a/nss/getpwnam.c b/nss/getpwnam.c
> index 36d5a43fd6..55578f7fc0 100644
> --- a/nss/getpwnam.c
> +++ b/nss/getpwnam.c
> @@ -17,12 +17,10 @@
>   
>   #include <pwd.h>
>   
> +#include <nss_generic.h>
>   
> -#define LOOKUP_TYPE	struct passwd
> -#define FUNCTION_NAME	getpwnam
> -#define DATABASE_NAME	passwd
> -#define ADD_PARAMS	const char *name
> -#define ADD_VARIABLES	name
> -#define BUFLEN		NSS_BUFLEN_PASSWD
> -
> -#include "../nss/getXXbyYY.c"
> +struct passwd *
> +getpwnam (const char *name)
> +{
> +  return __nss_getX (nss_lookup_getpwnam, name);
> +}
> diff --git a/nss/getpwnam_r.c b/nss/getpwnam_r.c
> index 1ba6ba53c9..2bb0bfa5e1 100644
> --- a/nss/getpwnam_r.c
> +++ b/nss/getpwnam_r.c
> @@ -17,12 +17,31 @@
>   
>   #include <pwd.h>
>   
> +#include <nss_generic.h>
> +#include <shlib-compat.h>
>   
> -#define LOOKUP_TYPE	struct passwd
> -#define FUNCTION_NAME	getpwnam
> -#define DATABASE_NAME	passwd
> -#define ADD_PARAMS	const char *name
> -#define ADD_VARIABLES	name
> -#define BUFLEN		NSS_BUFLEN_PASSWD
> +int
> +___getpwnam_r (const char *name, struct passwd *pwd,
> +	      char *buffer, size_t length, struct passwd **result)
> +{
> +  void *ptr = pwd;
> +  int ret = __nss_getX_r (nss_lookup_getpwnam, name, &ptr, buffer, length);
> +  *result = ptr;
> +  return ret;
> +}
> +strong_alias (___getpwnam_r, __getpwnam_r)
> +versioned_symbol (libc, ___getpwnam_r, getpwnam_r, GLIBC_2_1_2);
>   
> -#include <nss/getXXbyYY_r.c>
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1_2)
> +int
> +attribute_compat_text_section
> +__old_getpwnam_r (const char *name, struct passwd *pwd,
> +		   char *buffer, size_t length, struct passwd **result)
> +{
> +  int ret = __getpwnam_r (name, pwd, buffer, length, result);
> +  if (ret != 0 || result == NULL)
> +    ret = -1;
> +  return ret;
> +}
> +compat_symbol (libc, __old_getpwnam_r, getpwnam_r, GLIBC_2_0);
> +#endif
> diff --git a/nss/getpwuid.c b/nss/getpwuid.c
> index 9002dbbc34..96cccdcd89 100644
> --- a/nss/getpwuid.c
> +++ b/nss/getpwuid.c
> @@ -17,12 +17,10 @@
>   
>   #include <pwd.h>
>   
> +#include <nss_generic.h>
>   
> -#define LOOKUP_TYPE	struct passwd
> -#define FUNCTION_NAME	getpwuid
> -#define DATABASE_NAME	passwd
> -#define ADD_PARAMS	uid_t uid
> -#define ADD_VARIABLES	uid
> -#define BUFLEN		NSS_BUFLEN_PASSWD
> -
> -#include "../nss/getXXbyYY.c"
> +struct passwd *
> +getpwuid (uid_t uid)
> +{
> +  return __nss_getX (nss_lookup_getpwuid, &uid);
> +}
> diff --git a/nss/getpwuid_r.c b/nss/getpwuid_r.c
> index 7c6f3970fa..d99846bb57 100644
> --- a/nss/getpwuid_r.c
> +++ b/nss/getpwuid_r.c
> @@ -17,12 +17,31 @@
>   
>   #include <pwd.h>
>   
> +#include <nss_generic.h>
> +#include <shlib-compat.h>
>   
> -#define LOOKUP_TYPE	struct passwd
> -#define FUNCTION_NAME	getpwuid
> -#define DATABASE_NAME	passwd
> -#define ADD_PARAMS	uid_t uid
> -#define ADD_VARIABLES	uid
> -#define BUFLEN		NSS_BUFLEN_PASSWD
> +int
> +___getpwuid_r (uid_t uid, struct passwd *pwd,
> +              char *buffer, size_t length, struct passwd **result)
> +{
> +  void *ptr = pwd;
> +  int ret = __nss_getX_r (nss_lookup_getpwuid, &uid, &ptr, buffer, length);
> +  *result = ptr;
> +  return ret;
> +}
> +strong_alias (___getpwuid_r, __getpwuid_r)
> +versioned_symbol (libc, ___getpwuid_r, getpwuid_r, GLIBC_2_1_2);
>   
> -#include <nss/getXXbyYY_r.c>
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1_2)
> +int
> +attribute_compat_text_section
> +__old_getpwuid_r (uid_t uid, struct passwd *pwd,
> +                   char *buffer, size_t length, struct passwd **result)
> +{
> +  int ret = __getpwuid_r (uid, pwd, buffer, length, result);
> +  if (ret != 0 || result == NULL)
> +    ret = -1;
> +  return ret;
> +}
> +compat_symbol (libc, __old_getpwuid_r, getpwuid_r, GLIBC_2_0);
> +#endif
> diff --git a/nss/nss_generic.h b/nss/nss_generic.h
> index 8a5b2cb896..107ebb2003 100644
> --- a/nss/nss_generic.h
> +++ b/nss/nss_generic.h
> @@ -80,4 +80,67 @@ typedef const void *nss_lookup_key;
>   bool __nscd_generic_get (enum nss_lookup_type lt, nss_lookup_key key,
>                            void **result);
>   
> +/* Invokes the NSS module function SERVICE_FUNCTION of type LT using
> +   KEY.  The caller must initialize *RESULT to point to storage of
> +   the appropriate NSS struct for LT.  Upon return, the function
> +   may write NULL to *RESULT and return with an error
> +   (including triggering the ERANGE protocol), or leave *RESULT
> +   unchanged and fill the struct with data, potentially using
> +   LENGTH bytes at BUFFER for additional storage.  */
> +enum nss_status __nss_generic_get_r (enum nss_lookup_type lt,
> +                                     nss_lookup_key key,
> +                                     void *service_function,
> +                                     void **result,
> +                                     char *buffer,
> +                                     size_t length) attribute_hidden;
> +
> +/* Like __nss_generic_get_r, but handles the ERANGE protocol.
> +   *RESULT is not read, but overwritten with a malloc-allocated
> +   pointer or NULL.  */
> +enum nss_status __nss_generic_get (enum nss_lookup_type lt,
> +                                   nss_lookup_key key,
> +                                   void *service_function,
> +                                   void **result) attribute_hidden;
> +
> +/* Returns the pointer to the first service lookup function for lookup
> +   type LT, or NULL if there are no service modules.  Updates *NIP
> +   accordingly.  */
> +void *__nss_generic_lookup (enum nss_lookup_type lt, nss_action_list *ni)
> +  attribute_hidden;
> +
> +/* See __nss_next2 in <nsswitch.h>.  The function names are selected
> +   based on the type LT.  */
> +int __nss_generic_next (enum nss_lookup_type lt, nss_action_list *ni,
> +                        void *fctp, int status, int all_values)
> +  attribute_hidden;
> +
> +/* Perform a group lookup with merging.  On success, return zero and
> +   write a malloc-allocated struct group pointer to *RESULT (positive
> +   result) or NULL (negative result).  On failure, return -1 and write
> +   NULL to *RESULT, and set errno accordingly.  */
> +int __nss_getXinfo (enum nss_lookup_type lt,
> +                    nss_lookup_key key, void **result) attribute_hidden;
> +
> +/* Like __nss_getXinfo, but LT must be nss_lookup_getgrgid or
> +   nss_lookup_getgrnam.  This function does not contact nscd and is
> +   used in the implementation of __nss_getXInfo.  */
> +int __nss_getgrXinfo (enum nss_lookup_type lt,
> +                      nss_lookup_key key, void **result) attribute_hidden;
> +
> +/* Implementation of the non-_r public interface.  RESULT must be the
> +   address of the global variable.  It is freed before the lookup
> +   starts.  Returns NULL on failure, and a pointer to the NSS struct
> +   appropriate for LT on success.  Negative lookup returns NULL and
> +   does not set errno.  Other errors set errno.  */
> +void *__nss_getX (enum nss_lookup_type lt, nss_lookup_key key)
> +  attribute_hidden;
> +
> +/* Implementation of the _r public interface.  The caller must
> +   initialize *RESULT with the address of the result structure passed
> +   to the _r function.  Return 0 on success and error code on
> +   failure (including ERANGE).  */
> +int __nss_getX_r (enum nss_lookup_type lt, nss_lookup_key key,
> +                  void **result, char *buffer, size_t length)
> +  attribute_hidden;
> +
>   #endif /* NSS_GENERIC_H */
> diff --git a/nss/nss_generic_get.c b/nss/nss_generic_get.c
> new file mode 100644
> index 0000000000..3319a2b9c0
> --- /dev/null
> +++ b/nss/nss_generic_get.c
> @@ -0,0 +1,61 @@
> +/* Implementation of the ERANGE protocol for service module functions.
> +   Copyright (C) 2026 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_generic.h>
> +#include <nss_generic_storage.h>
> +#include <scratch_buffer.h>
> +
> +enum nss_status
> +__nss_generic_get (enum nss_lookup_type lt,
> +                   nss_lookup_key key,
> +                   void *service_function,
> +                   void **result)
> +{
> +  struct scratch_buffer buf;
> +  scratch_buffer_init (&buf);
> +
> +  *result = NULL;
> +  while (true)
> +    {
> +      union nss_generic_storage storage;
> +      void *ptr = &storage;
> +      enum nss_status status = __nss_generic_get_r (lt, key,
> +                                                    service_function, &ptr,
> +                                                    buf.data, buf.length);
> +      if (status == NSS_STATUS_TRYAGAIN && errno == ERANGE)
> +        {
> +          if (!scratch_buffer_grow (&buf))
> +            return status;
> +        }
> +      else
> +        {
> +          if (status == NSS_STATUS_SUCCESS)
> +            {
> +              if (ptr != NULL)
> +                {
> +                  ptr = __nss_generic_dup (lt, ptr);
> +                  if (ptr == NULL)
> +                    status = NSS_STATUS_TRYAGAIN;
> +                  *result = ptr;
> +                }
> +            }
> +          scratch_buffer_free (&buf);
> +          return status;
> +        }
> +    }
> +}
> diff --git a/nss/nss_generic_get_r.c b/nss/nss_generic_get_r.c
> new file mode 100644
> index 0000000000..12fedee10f
> --- /dev/null
> +++ b/nss/nss_generic_get_r.c
> @@ -0,0 +1,45 @@
> +/* Lookup-independent call to an NSS service function.
> +   Copyright (C) 2026 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_generic.h>
> +
> +enum nss_status
> +__nss_generic_get_r (enum nss_lookup_type lt,
> +                     nss_lookup_key key,
> +                     void *service_function,
> +                     void **result,
> +                     char *buffer,
> +                     size_t length)
> +{
> +  switch (lt)
> +    {
> +      case nss_lookup_getgrgid:
> +        return ((nss_getgrgid_r *) service_function)
> +          (*(const gid_t *) key, *result, buffer, length, &errno);
> +      case nss_lookup_getgrnam:
> +        return ((nss_getgrnam_r *) service_function)
> +          (key, *result, buffer, length, &errno);
> +      case nss_lookup_getpwnam:
> +        return ((nss_getpwnam_r *) service_function)
> +          (key, *result, buffer, length, &errno);
> +      case nss_lookup_getpwuid:
> +        return ((nss_getpwuid_r *) service_function)
> +          (*(const uid_t *) key, *result, buffer, length, &errno);
> +    }
> +  __builtin_unreachable ();
> +}
> diff --git a/nss/nss_generic_lookup.c b/nss/nss_generic_lookup.c
> new file mode 100644
> index 0000000000..f9e41311bc
> --- /dev/null
> +++ b/nss/nss_generic_lookup.c
> @@ -0,0 +1,51 @@
> +/* Type-generic lookup of the first NSS service module function.
> +   Copyright (C) 2026 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 <assert.h>
> +#include <nss_generic.h>
> +
> +void *
> +__nss_generic_lookup (enum nss_lookup_type lt, nss_action_list *ni)
> +{
> +  int database;
> +  const char *fct_name;
> +  const char *fct2_name = NULL;
> +
> +  switch (lt)
> +    {
> +#define DEFINE_LOOKUP(name, dbname, function, nscddb)   \
> +      case nss_lookup_##name:                           \
> +        database = nss_database_##dbname;               \
> +        fct_name = function;                            \
> +        break;
> +#include <nss-lookups.def>
> +#undef DEFINE_LOOKUP
> +    default:
> +      abort ();
> +    }
> +
> +  if (! __nss_database_get (database, ni))
> +    return NULL;
> +
> +  assert (*ni != NULL);
> +  void *fct;
> +  if (__nss_lookup (ni, fct_name, fct2_name, &fct) == 0)
> +    return fct;
> +  else
> +    return NULL;
> +}
> diff --git a/nss/nss_generic_next.c b/nss/nss_generic_next.c
> new file mode 100644
> index 0000000000..abc5a61e11
> --- /dev/null
> +++ b/nss/nss_generic_next.c
> @@ -0,0 +1,60 @@
> +/* Type-generic next NSS service module function lookup.
> +   Copyright (C) 2026 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 <assert.h>
> +#include <nss_generic.h>
> +
> +int
> +__nss_generic_next (enum nss_lookup_type lt, nss_action_list *ni,
> +                    void *fctp, int status, int all_values)
> +{
> +  /* Extract the database index and function name from <nss-lookups.def>.  */
> +  int database;
> +  const char *fct_name;
> +
> +  switch (lt)
> +    {
> +#define DEFINE_LOOKUP(name, dbname, function, nscddb)   \
> +      case nss_lookup_##name:                           \
> +        database = nss_database_##dbname;               \
> +        fct_name = function;                            \
> +        break;
> +#include <nss-lookups.def>
> +#undef DEFINE_LOOKUP
> +    default:
> +      abort ();
> +    }
> +
> +  /* No secondary functions yet.  */
> +  const char *fct2_name = NULL;
> +
> +  int ret;
> +  if (*ni == NULL)
> +    {
> +      /* First call.  Ignore status and all_values.  */
> +      if (! __nss_database_get (database, ni))
> +        return -1;
> +
> +      assert (*ni != NULL);
> +      ret = __nss_lookup (ni, fct_name, fct2_name, fctp);
> +    }
> +  else
> +    ret = __nss_next2 (ni, fct_name, fct2_name, fctp, status, all_values);
> +
> +  return ret;
> +}
> diff --git a/nss/nss_generic_storage.h b/nss/nss_generic_storage.h
> new file mode 100644
> index 0000000000..334f51be70
> --- /dev/null
> +++ b/nss/nss_generic_storage.h
> @@ -0,0 +1,30 @@
> +/* Type that can hold all NSS structs.
> +   Copyright (C) 2026 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/>.  */
> +
> +#ifndef NSS_GENERIC_STORAGE
> +#define NSS_GENERIC_STORAGE
> +
> +#include <grp.h>
> +#include <pwd.h>
> +
> +union nss_generic_storage
> +{
> +  struct passwd pwd;
> +};
> +
> +#endif /* NSS_GENERIC_STORAGE */
> diff --git a/nss/nss_getX.c b/nss/nss_getX.c
> new file mode 100644
> index 0000000000..8595e5e3b0
> --- /dev/null
> +++ b/nss/nss_getX.c
> @@ -0,0 +1,53 @@
> +/* Type-generic implementation of public non-_r NSS legacy functions.
> +   Copyright (C) 2026 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 <array_length.h>
> +#include <libc-lock.h>
> +#include <nss_generic.h>
> +#include <set-freeres.h>
> +#include <stdlib.h>
> +
> +static void *__nss_generic_allocation[nss_lookup_MAX];
> +static __libc_lock_t __nss_generic_lock[nss_lookup_MAX];
> +
> +void *
> +__nss_getX (enum nss_lookup_type lt, nss_lookup_key key)
> +{
> +  __libc_lock_lock (__nss_generic_lock[lt]);
> +  free (__nss_generic_allocation[lt]);
> +  __nss_generic_allocation[lt] = NULL;
> +
> +  /* Preserve errno (possibly 0) if ret == 0.  */
> +  int saved_errno = errno;
> +  void *result;
> +  int ret = __nss_getXinfo (lt, key, &result);
> +  __nss_generic_allocation[lt] = result;
> +
> +  __libc_lock_unlock (__nss_generic_lock[lt]);
> +  if (ret == 0)
> +    __set_errno (saved_errno);
> +
> +  return result;
> +}
> +
> +void
> +__nss_generic_freeres (void)
> +{
> +  for (int i = 0; i < array_length (__nss_generic_allocation); ++i)
> +    free (__nss_generic_allocation[i]);
> +}
> diff --git a/nss/nss_getX_r.c b/nss/nss_getX_r.c
> new file mode 100644
> index 0000000000..b0d488c889
> --- /dev/null
> +++ b/nss/nss_getX_r.c
> @@ -0,0 +1,45 @@
> +/* Type-generic implementation of public NSS get*_r functions.
> +   Copyright (C) 2026 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 <errno.h>
> +#include <nss_generic.h>
> +#include <stdlib.h>
> +
> +int
> +__nss_getX_r (enum nss_lookup_type lt, nss_lookup_key key,
> +              void **result, char *buffer, size_t length)
> +{
> +  void *storage = *result;
> +  *result = NULL;
> +
> +  void *allocated;
> +  int ret = __nss_getXinfo (lt, key, &allocated);
> +  if (ret == 0)
> +    {
> +      if (allocated != NULL)
> +        {
> +          ret = __nss_generic_copy (lt, allocated, storage, buffer, length);
> +          if (ret == 0)
> +            *result = storage;
> +          free (allocated);
> +        }
> +      return ret;
> +    }
> +  else
> +    return errno;
> +}
> diff --git a/nss/nss_getXinfo.c b/nss/nss_getXinfo.c
> new file mode 100644
> index 0000000000..0b2588c9fd
> --- /dev/null
> +++ b/nss/nss_getXinfo.c
> @@ -0,0 +1,67 @@
> +/* Generic malloc-compatible version of NSS get functions.
> +   Copyright (C) 2026 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_generic.h>
> +
> +int
> +__nss_getXinfo (enum nss_lookup_type lt, nss_lookup_key key, void **result)
> +{
> +#ifdef USE_NSCD
> +  if (__nscd_generic_get (lt, key, result))
> +    return 0;
> +#endif
> +
> +  nss_action_list nip = NULL;
> +  void *fct;
> +  int no_more = __nss_generic_next (lt, &nip, &fct, 0, 0);
> +  enum nss_status status = NSS_STATUS_UNAVAIL;
> +
> +  *result = NULL;
> +  while (no_more == 0)
> +    {
> +      void *ptr;
> +      status = __nss_generic_get (lt, key, fct, &ptr);
> +      if (status == NSS_STATUS_SUCCESS)
> +        {
> +          free (*result);
> +          *result = ptr;
> +        }
> +
> +      /* MERGE is invalid for most databases.  */
> +      if ((nss_next_action (nip, status) == NSS_ACTION_MERGE
> +           && status == NSS_STATUS_SUCCESS))
> +        {
> +          __set_errno (EINVAL);
> +          status = NSS_STATUS_UNAVAIL;
> +          break;
> +        }
> +
> +      no_more = __nss_generic_next (lt, &nip, &fct, status, 0);
> +    }
> +
> +  if (status != NSS_STATUS_SUCCESS)
> +    {
> +      free (*result);
> +      *result = NULL;
> +    }
> +
> +  if (status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND)
> +    return 0;
> +  else
> +    return errno;
> +}


-- 
Cheers,
Carlos.



More information about the Libc-alpha mailing list