[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