[PATCH v2 20/23] nss: Convert passwd database to new NSS framework
Florian Weimer
fweimer@redhat.com
Fri Mar 20 20:43:07 GMT 2026
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.
---
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 \
nss_generic_nscd \
+ nss_getX \
+ nss_getX_r \
+ nss_getXinfo \
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;
+}
--
2.53.0
More information about the Libc-alpha
mailing list