[v2,23/23] nss: Remove old group merge code

Message ID 05e0a557343d05d4406b3776e13af4b1147b1541.1774037705.git.fweimer@redhat.com (mailing list archive)
State Failed CI
Headers
Series NSS, nscd updates (for group merging and more) |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch success Patch applied to master at the time it was sent
linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_glibc_build--master-arm success Build passed
redhat-pt-bot/TryBot-32bit fail Patch caused testsuite regressions
linaro-tcwg-bot/tcwg_glibc_check--master-arm fail Test failed
linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 fail Test failed

Commit Message

Florian Weimer March 20, 2026, 8:43 p.m. UTC
  ---
 nss/Makefile      |   1 -
 nss/getXXbyYY_r.c | 107 ++-----------------------
 nss/grp-merge.c   | 200 ----------------------------------------------
 nss/grp-merge.h   |  35 --------
 4 files changed, 7 insertions(+), 336 deletions(-)
 delete mode 100644 nss/grp-merge.c
 delete mode 100644 nss/grp-merge.h
  

Comments

Carlos O'Donell March 24, 2026, 9:59 p.m. UTC | #1
On 3/20/26 4:43 PM, Florian Weimer wrote:

LGTM. Nice removal :-)

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

> ---
>   nss/Makefile      |   1 -
>   nss/getXXbyYY_r.c | 107 ++-----------------------
>   nss/grp-merge.c   | 200 ----------------------------------------------
>   nss/grp-merge.h   |  35 --------
>   4 files changed, 7 insertions(+), 336 deletions(-)
>   delete mode 100644 nss/grp-merge.c
>   delete mode 100644 nss/grp-merge.h
> 
> diff --git a/nss/Makefile b/nss/Makefile
> index 504f573478..36cf9aa63c 100644
> --- a/nss/Makefile
> +++ b/nss/Makefile
> @@ -95,7 +95,6 @@ routines += \
>     getgrgid_r \
>     getgrnam \
>     getgrnam_r \
> -  grp-merge \
>     initgroups \
>     nss_group_members \
>     putgrent \
> diff --git a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c
> index 9527b6722d..aa262634f9 100644
> --- a/nss/getXXbyYY_r.c
> +++ b/nss/getXXbyYY_r.c
> @@ -126,47 +126,6 @@
>   #endif
>   
>   
> -/* Set defaults for merge functions that haven't been defined.  */
> -#ifndef DEEPCOPY_FN
> -static inline int
> -__copy_einval (LOOKUP_TYPE a,
> -	       const size_t b,
> -	       LOOKUP_TYPE *c,
> -	       char *d,
> -	       char **e)
> -{
> -  return EINVAL;
> -}
> -# define DEEPCOPY_FN __copy_einval
> -#endif
> -
> -#ifndef MERGE_FN
> -static inline int
> -__merge_einval (LOOKUP_TYPE *a,
> -		char *b,
> -		char *c,
> -		size_t d,
> -		LOOKUP_TYPE *e,
> -		char *f)
> -{
> -  return EINVAL;
> -}
> -# define MERGE_FN __merge_einval
> -#endif
> -
> -#define CHECK_MERGE(err, status)		\
> -  ({						\
> -    if (err)					\
> -      {						\
> -	__set_errno (err);			\
> -	if (err == ERANGE)			\
> -	  status = NSS_STATUS_TRYAGAIN;		\
> -	else					\
> -	  status = NSS_STATUS_UNAVAIL;		\
> -	break;					\
> -      }						\
> -  })
> -
>   /* Type of the lookup function we need here.  */
>   typedef enum nss_status (*lookup_function) (ADD_PARAMS, LOOKUP_TYPE *, char *,
>   					    size_t, int * H_ERRNO_PARM
> @@ -184,12 +143,8 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
>   			   EXTRA_PARAMS)
>   {
>     nss_action_list nip;
> -  int do_merge = 0;
> -  LOOKUP_TYPE mergegrp;
> -  char *mergebuf = NULL;
> -  char *endptr = NULL;
>     void *fct;
> -  int no_more, err;
> +  int no_more;
>     enum nss_status status = NSS_STATUS_UNAVAIL;
>   #ifdef USE_NSCD
>     int nscd_status;
> @@ -273,66 +228,18 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
>   	  && errno == ERANGE)
>   	break;
>   
> -      if (do_merge)
> -	{
> -
> -	  if (status == NSS_STATUS_SUCCESS)
> -	    {
> -	      /* The previous loop saved a buffer for merging.
> -		 Perform the merge now.  */
> -	      err = MERGE_FN (&mergegrp, mergebuf, endptr, buflen, resbuf,
> -			      buffer);
> -	      CHECK_MERGE (err,status);
> -	      do_merge = 0;
> -	    }
> -	  else
> -	    {
> -	      /* If the result wasn't SUCCESS, copy the saved buffer back
> -	         into the result buffer and set the status back to
> -	         NSS_STATUS_SUCCESS to match the previous pass through the
> -	         loop.
> -	          * If the next action is CONTINUE, it will overwrite the value
> -	            currently in the buffer and return the new value.
> -	          * If the next action is RETURN, we'll return the previously-
> -	            acquired values.
> -	          * If the next action is MERGE, then it will be added to the
> -	            buffer saved from the previous source.  */
> -	      err = DEEPCOPY_FN (mergegrp, buflen, resbuf, buffer, NULL);
> -	      CHECK_MERGE (err, status);
> -	      status = NSS_STATUS_SUCCESS;
> -	    }
> -	}
> -
> -      /* If we were are configured to merge this value with the next one,
> -         save the current value of the group struct.  */
> -      if (nss_next_action (nip, status) == NSS_ACTION_MERGE
> -	  && status == NSS_STATUS_SUCCESS)
> +      /* MERGE is invalid for most databases.  */
> +      if ((nss_next_action (nip, status) == NSS_ACTION_MERGE
> +	   && status == NSS_STATUS_SUCCESS))
>   	{
> -	  /* Copy the current values into a buffer to be merged with the next
> -	     set of retrieved values.  */
> -	  if (mergebuf == NULL)
> -	    {
> -	      /* Only allocate once and reuse it for as many merges as we need
> -	         to perform.  */
> -	      mergebuf = malloc (buflen);
> -	      if (mergebuf == NULL)
> -		{
> -		  __set_errno (ENOMEM);
> -		  status = NSS_STATUS_UNAVAIL;
> -		  break;
> -		}
> -	    }
> -
> -	  err = DEEPCOPY_FN (*resbuf, buflen, &mergegrp, mergebuf, &endptr);
> -	  CHECK_MERGE (err, status);
> -	  do_merge = 1;
> +	  __set_errno (EINVAL);
> +	  status = NSS_STATUS_UNAVAIL;
> +	  break;
>   	}
>   
>         no_more = __nss_next2 (&nip, REENTRANT_NAME_STRING,
>   			     REENTRANT2_NAME_STRING, &fct, status, 0);
>       }
> -  free (mergebuf);
> -  mergebuf = NULL;
>   
>   #ifdef HANDLE_DIGITS_DOTS
>   done:
> diff --git a/nss/grp-merge.c b/nss/grp-merge.c
> deleted file mode 100644
> index 0a99882097..0000000000
> --- a/nss/grp-merge.c
> +++ /dev/null
> @@ -1,200 +0,0 @@
> -/* Group merging implementation.
> -   Copyright (C) 2016-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 <stdlib.h>
> -#include <string.h>
> -#include <grp.h>
> -#include <grp-merge.h>
> -
> -#define BUFCHECK(size)			\
> -  ({					\
> -    do					\
> -      {					\
> -	if (c + (size) > buflen)	\
> -          {				\
> -	    free (members);		\
> -	    return ERANGE;		\
> -	  }				\
> -      }					\
> -    while (0);				\
> -  })
> -
> -int
> -__copy_grp (const struct group srcgrp, const size_t buflen,
> -	    struct group *destgrp, char *destbuf, char **endptr)
> -{
> -  size_t i;
> -  size_t c = 0;
> -  size_t len;
> -  size_t memcount;
> -  char **members = NULL;
> -
> -  /* Copy the GID.  */
> -  destgrp->gr_gid = srcgrp.gr_gid;
> -
> -  /* Copy the name.  */
> -  len = strlen (srcgrp.gr_name) + 1;
> -  BUFCHECK (len);
> -  memcpy (&destbuf[c], srcgrp.gr_name, len);
> -  destgrp->gr_name = &destbuf[c];
> -  c += len;
> -
> -  /* Copy the password.  */
> -  len = strlen (srcgrp.gr_passwd) + 1;
> -  BUFCHECK (len);
> -  memcpy (&destbuf[c], srcgrp.gr_passwd, len);
> -  destgrp->gr_passwd = &destbuf[c];
> -  c += len;
> -
> -  /* Count all of the members.  */
> -  for (memcount = 0; srcgrp.gr_mem[memcount]; memcount++)
> -    ;
> -
> -  /* Allocate a temporary holding area for the pointers to the member
> -     contents, including space for a NULL-terminator.  */
> -  members = malloc (sizeof (char *) * (memcount + 1));
> -  if (members == NULL)
> -    return ENOMEM;
> -
> -  /* Copy all of the group members to destbuf and add a pointer to each of
> -     them into the 'members' array.  */
> -  for (i = 0; srcgrp.gr_mem[i]; i++)
> -    {
> -      len = strlen (srcgrp.gr_mem[i]) + 1;
> -      BUFCHECK (len);
> -      memcpy (&destbuf[c], srcgrp.gr_mem[i], len);
> -      members[i] = &destbuf[c];
> -      c += len;
> -    }
> -  members[i] = NULL;
> -
> -  /* Align for pointers.  We can't simply align C because we need to
> -     align destbuf[c].  */
> -  if ((((uintptr_t)destbuf + c) & (__alignof__(char **) - 1)) != 0)
> -    {
> -      uintptr_t mis_align = ((uintptr_t)destbuf + c) & (__alignof__(char **) - 1);
> -      c += __alignof__(char **) - mis_align;
> -    }
> -
> -  /* Copy the pointers from the members array into the buffer and assign them
> -     to the gr_mem member of destgrp.  */
> -  destgrp->gr_mem = (char **) &destbuf[c];
> -  len = sizeof (char *) * (memcount + 1);
> -  BUFCHECK (len);
> -  memcpy (&destbuf[c], members, len);
> -  c += len;
> -  free (members);
> -  members = NULL;
> -
> -  /* Save the count of members at the end.  */
> -  BUFCHECK (sizeof (size_t));
> -  memcpy (&destbuf[c], &memcount, sizeof (size_t));
> -  c += sizeof (size_t);
> -
> -  if (endptr)
> -    *endptr = destbuf + c;
> -  return 0;
> -}
> -libc_hidden_def (__copy_grp)
> -
> -/* Check that the name, GID and passwd fields match, then
> -   copy in the gr_mem array.  */
> -int
> -__merge_grp (struct group *savedgrp, char *savedbuf, char *savedend,
> -	     size_t buflen, struct group *mergegrp, char *mergebuf)
> -{
> -  size_t c, i, len;
> -  size_t savedmemcount;
> -  size_t memcount;
> -  size_t membersize;
> -  char **members = NULL;
> -
> -  /* We only support merging members of groups with identical names and
> -     GID values. If we hit this case, we need to overwrite the current
> -     buffer with the saved one (which is functionally equivalent to
> -     treating the new lookup as NSS_STATUS_NOTFOUND).  */
> -  if (mergegrp->gr_gid != savedgrp->gr_gid
> -      || strcmp (mergegrp->gr_name, savedgrp->gr_name))
> -    return __copy_grp (*savedgrp, buflen, mergegrp, mergebuf, NULL);
> -
> -  /* Get the count of group members from the last sizeof (size_t) bytes in the
> -     mergegrp buffer.  */
> -  savedmemcount = *(size_t *) (savedend - sizeof (size_t));
> -
> -  /* Get the count of new members to add.  */
> -  for (memcount = 0; mergegrp->gr_mem[memcount]; memcount++)
> -    ;
> -
> -  /* Create a temporary array to hold the pointers to the member values from
> -     both the saved and merge groups.  */
> -  membersize = savedmemcount + memcount + 1;
> -  members = malloc (sizeof (char *) * membersize);
> -  if (members == NULL)
> -    return ENOMEM;
> -
> -  /* Copy in the existing member pointers from the saved group
> -     Note: this is not NULL-terminated yet.  */
> -  memcpy (members, savedgrp->gr_mem, sizeof (char *) * savedmemcount);
> -
> -  /* Back up into the savedbuf until we get back to the NULL-terminator of the
> -     group member list. (This means walking back savedmemcount + 1 (char *) pointers
> -     and the member count value.
> -     The value of c is going to be the used length of the buffer backed up by
> -     the member count and further backed up by the size of the pointers.  */
> -  c = savedend - savedbuf
> -      - sizeof (size_t)
> -      - sizeof (char *) * (savedmemcount + 1);
> -
> -  /* Add all the new group members, overwriting the old NULL-terminator while
> -     adding the new pointers to the temporary array.  */
> -  for (i = 0; mergegrp->gr_mem[i]; i++)
> -    {
> -      len = strlen (mergegrp->gr_mem[i]) + 1;
> -      BUFCHECK (len);
> -      memcpy (&savedbuf[c], mergegrp->gr_mem[i], len);
> -      members[savedmemcount + i] = &savedbuf[c];
> -      c += len;
> -    }
> -  /* Add the NULL-terminator.  */
> -  members[savedmemcount + memcount] = NULL;
> -
> -  /* Align for pointers.  We can't simply align C because we need to
> -     align savedbuf[c].  */
> -  if ((((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1)) != 0)
> -    {
> -      uintptr_t mis_align = ((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1);
> -      c += __alignof__(char **) - mis_align;
> -    }
> -
> -  /* Copy the member array back into the buffer after the member list and free
> -     the member array.  */
> -  savedgrp->gr_mem = (char **) &savedbuf[c];
> -  len = sizeof (char *) * membersize;
> -  BUFCHECK (len);
> -  memcpy (&savedbuf[c], members, len);
> -  c += len;
> -
> -  free (members);
> -  members = NULL;
> -
> -  /* Finally, copy the results back into mergebuf, since that's the buffer
> -     that we were provided by the caller.  */
> -  return __copy_grp (*savedgrp, buflen, mergegrp, mergebuf, NULL);
> -}
> -libc_hidden_def (__merge_grp)
> diff --git a/nss/grp-merge.h b/nss/grp-merge.h
> deleted file mode 100644
> index ba985c556e..0000000000
> --- a/nss/grp-merge.h
> +++ /dev/null
> @@ -1,35 +0,0 @@
> -/* Group merging implementation.
> -   Copyright (C) 2016-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 _GRP_MERGE_H
> -#define _GRP_MERGE_H 1
> -
> -#include <grp.h>
> -
> -/* Duplicate a grp struct (and its members). When no longer needed, the
> -   calling function must free(newbuf).  */
> -int
> -__copy_grp (const struct group srcgrp, const size_t buflen,
> -	    struct group *destgrp, char *destbuf, char **endptr);
> -
> -/* Merge the member lists of two grp structs together.  */
> -int
> -__merge_grp (struct group *savedgrp, char *savedbuf, char *savedend,
> -	     size_t buflen, struct group *mergegrp, char *mergebuf);
> -
> -#endif /* _GRP_MERGE_H */
  

Patch

diff --git a/nss/Makefile b/nss/Makefile
index 504f573478..36cf9aa63c 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -95,7 +95,6 @@  routines += \
   getgrgid_r \
   getgrnam \
   getgrnam_r \
-  grp-merge \
   initgroups \
   nss_group_members \
   putgrent \
diff --git a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c
index 9527b6722d..aa262634f9 100644
--- a/nss/getXXbyYY_r.c
+++ b/nss/getXXbyYY_r.c
@@ -126,47 +126,6 @@ 
 #endif
 
 
-/* Set defaults for merge functions that haven't been defined.  */
-#ifndef DEEPCOPY_FN
-static inline int
-__copy_einval (LOOKUP_TYPE a,
-	       const size_t b,
-	       LOOKUP_TYPE *c,
-	       char *d,
-	       char **e)
-{
-  return EINVAL;
-}
-# define DEEPCOPY_FN __copy_einval
-#endif
-
-#ifndef MERGE_FN
-static inline int
-__merge_einval (LOOKUP_TYPE *a,
-		char *b,
-		char *c,
-		size_t d,
-		LOOKUP_TYPE *e,
-		char *f)
-{
-  return EINVAL;
-}
-# define MERGE_FN __merge_einval
-#endif
-
-#define CHECK_MERGE(err, status)		\
-  ({						\
-    if (err)					\
-      {						\
-	__set_errno (err);			\
-	if (err == ERANGE)			\
-	  status = NSS_STATUS_TRYAGAIN;		\
-	else					\
-	  status = NSS_STATUS_UNAVAIL;		\
-	break;					\
-      }						\
-  })
-
 /* Type of the lookup function we need here.  */
 typedef enum nss_status (*lookup_function) (ADD_PARAMS, LOOKUP_TYPE *, char *,
 					    size_t, int * H_ERRNO_PARM
@@ -184,12 +143,8 @@  INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
 			   EXTRA_PARAMS)
 {
   nss_action_list nip;
-  int do_merge = 0;
-  LOOKUP_TYPE mergegrp;
-  char *mergebuf = NULL;
-  char *endptr = NULL;
   void *fct;
-  int no_more, err;
+  int no_more;
   enum nss_status status = NSS_STATUS_UNAVAIL;
 #ifdef USE_NSCD
   int nscd_status;
@@ -273,66 +228,18 @@  INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
 	  && errno == ERANGE)
 	break;
 
-      if (do_merge)
-	{
-
-	  if (status == NSS_STATUS_SUCCESS)
-	    {
-	      /* The previous loop saved a buffer for merging.
-		 Perform the merge now.  */
-	      err = MERGE_FN (&mergegrp, mergebuf, endptr, buflen, resbuf,
-			      buffer);
-	      CHECK_MERGE (err,status);
-	      do_merge = 0;
-	    }
-	  else
-	    {
-	      /* If the result wasn't SUCCESS, copy the saved buffer back
-	         into the result buffer and set the status back to
-	         NSS_STATUS_SUCCESS to match the previous pass through the
-	         loop.
-	          * If the next action is CONTINUE, it will overwrite the value
-	            currently in the buffer and return the new value.
-	          * If the next action is RETURN, we'll return the previously-
-	            acquired values.
-	          * If the next action is MERGE, then it will be added to the
-	            buffer saved from the previous source.  */
-	      err = DEEPCOPY_FN (mergegrp, buflen, resbuf, buffer, NULL);
-	      CHECK_MERGE (err, status);
-	      status = NSS_STATUS_SUCCESS;
-	    }
-	}
-
-      /* If we were are configured to merge this value with the next one,
-         save the current value of the group struct.  */
-      if (nss_next_action (nip, status) == NSS_ACTION_MERGE
-	  && status == NSS_STATUS_SUCCESS)
+      /* MERGE is invalid for most databases.  */
+      if ((nss_next_action (nip, status) == NSS_ACTION_MERGE
+	   && status == NSS_STATUS_SUCCESS))
 	{
-	  /* Copy the current values into a buffer to be merged with the next
-	     set of retrieved values.  */
-	  if (mergebuf == NULL)
-	    {
-	      /* Only allocate once and reuse it for as many merges as we need
-	         to perform.  */
-	      mergebuf = malloc (buflen);
-	      if (mergebuf == NULL)
-		{
-		  __set_errno (ENOMEM);
-		  status = NSS_STATUS_UNAVAIL;
-		  break;
-		}
-	    }
-
-	  err = DEEPCOPY_FN (*resbuf, buflen, &mergegrp, mergebuf, &endptr);
-	  CHECK_MERGE (err, status);
-	  do_merge = 1;
+	  __set_errno (EINVAL);
+	  status = NSS_STATUS_UNAVAIL;
+	  break;
 	}
 
       no_more = __nss_next2 (&nip, REENTRANT_NAME_STRING,
 			     REENTRANT2_NAME_STRING, &fct, status, 0);
     }
-  free (mergebuf);
-  mergebuf = NULL;
 
 #ifdef HANDLE_DIGITS_DOTS
 done:
diff --git a/nss/grp-merge.c b/nss/grp-merge.c
deleted file mode 100644
index 0a99882097..0000000000
--- a/nss/grp-merge.c
+++ /dev/null
@@ -1,200 +0,0 @@ 
-/* Group merging implementation.
-   Copyright (C) 2016-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 <stdlib.h>
-#include <string.h>
-#include <grp.h>
-#include <grp-merge.h>
-
-#define BUFCHECK(size)			\
-  ({					\
-    do					\
-      {					\
-	if (c + (size) > buflen)	\
-          {				\
-	    free (members);		\
-	    return ERANGE;		\
-	  }				\
-      }					\
-    while (0);				\
-  })
-
-int
-__copy_grp (const struct group srcgrp, const size_t buflen,
-	    struct group *destgrp, char *destbuf, char **endptr)
-{
-  size_t i;
-  size_t c = 0;
-  size_t len;
-  size_t memcount;
-  char **members = NULL;
-
-  /* Copy the GID.  */
-  destgrp->gr_gid = srcgrp.gr_gid;
-
-  /* Copy the name.  */
-  len = strlen (srcgrp.gr_name) + 1;
-  BUFCHECK (len);
-  memcpy (&destbuf[c], srcgrp.gr_name, len);
-  destgrp->gr_name = &destbuf[c];
-  c += len;
-
-  /* Copy the password.  */
-  len = strlen (srcgrp.gr_passwd) + 1;
-  BUFCHECK (len);
-  memcpy (&destbuf[c], srcgrp.gr_passwd, len);
-  destgrp->gr_passwd = &destbuf[c];
-  c += len;
-
-  /* Count all of the members.  */
-  for (memcount = 0; srcgrp.gr_mem[memcount]; memcount++)
-    ;
-
-  /* Allocate a temporary holding area for the pointers to the member
-     contents, including space for a NULL-terminator.  */
-  members = malloc (sizeof (char *) * (memcount + 1));
-  if (members == NULL)
-    return ENOMEM;
-
-  /* Copy all of the group members to destbuf and add a pointer to each of
-     them into the 'members' array.  */
-  for (i = 0; srcgrp.gr_mem[i]; i++)
-    {
-      len = strlen (srcgrp.gr_mem[i]) + 1;
-      BUFCHECK (len);
-      memcpy (&destbuf[c], srcgrp.gr_mem[i], len);
-      members[i] = &destbuf[c];
-      c += len;
-    }
-  members[i] = NULL;
-
-  /* Align for pointers.  We can't simply align C because we need to
-     align destbuf[c].  */
-  if ((((uintptr_t)destbuf + c) & (__alignof__(char **) - 1)) != 0)
-    {
-      uintptr_t mis_align = ((uintptr_t)destbuf + c) & (__alignof__(char **) - 1);
-      c += __alignof__(char **) - mis_align;
-    }
-
-  /* Copy the pointers from the members array into the buffer and assign them
-     to the gr_mem member of destgrp.  */
-  destgrp->gr_mem = (char **) &destbuf[c];
-  len = sizeof (char *) * (memcount + 1);
-  BUFCHECK (len);
-  memcpy (&destbuf[c], members, len);
-  c += len;
-  free (members);
-  members = NULL;
-
-  /* Save the count of members at the end.  */
-  BUFCHECK (sizeof (size_t));
-  memcpy (&destbuf[c], &memcount, sizeof (size_t));
-  c += sizeof (size_t);
-
-  if (endptr)
-    *endptr = destbuf + c;
-  return 0;
-}
-libc_hidden_def (__copy_grp)
-
-/* Check that the name, GID and passwd fields match, then
-   copy in the gr_mem array.  */
-int
-__merge_grp (struct group *savedgrp, char *savedbuf, char *savedend,
-	     size_t buflen, struct group *mergegrp, char *mergebuf)
-{
-  size_t c, i, len;
-  size_t savedmemcount;
-  size_t memcount;
-  size_t membersize;
-  char **members = NULL;
-
-  /* We only support merging members of groups with identical names and
-     GID values. If we hit this case, we need to overwrite the current
-     buffer with the saved one (which is functionally equivalent to
-     treating the new lookup as NSS_STATUS_NOTFOUND).  */
-  if (mergegrp->gr_gid != savedgrp->gr_gid
-      || strcmp (mergegrp->gr_name, savedgrp->gr_name))
-    return __copy_grp (*savedgrp, buflen, mergegrp, mergebuf, NULL);
-
-  /* Get the count of group members from the last sizeof (size_t) bytes in the
-     mergegrp buffer.  */
-  savedmemcount = *(size_t *) (savedend - sizeof (size_t));
-
-  /* Get the count of new members to add.  */
-  for (memcount = 0; mergegrp->gr_mem[memcount]; memcount++)
-    ;
-
-  /* Create a temporary array to hold the pointers to the member values from
-     both the saved and merge groups.  */
-  membersize = savedmemcount + memcount + 1;
-  members = malloc (sizeof (char *) * membersize);
-  if (members == NULL)
-    return ENOMEM;
-
-  /* Copy in the existing member pointers from the saved group
-     Note: this is not NULL-terminated yet.  */
-  memcpy (members, savedgrp->gr_mem, sizeof (char *) * savedmemcount);
-
-  /* Back up into the savedbuf until we get back to the NULL-terminator of the
-     group member list. (This means walking back savedmemcount + 1 (char *) pointers
-     and the member count value.
-     The value of c is going to be the used length of the buffer backed up by
-     the member count and further backed up by the size of the pointers.  */
-  c = savedend - savedbuf
-      - sizeof (size_t)
-      - sizeof (char *) * (savedmemcount + 1);
-
-  /* Add all the new group members, overwriting the old NULL-terminator while
-     adding the new pointers to the temporary array.  */
-  for (i = 0; mergegrp->gr_mem[i]; i++)
-    {
-      len = strlen (mergegrp->gr_mem[i]) + 1;
-      BUFCHECK (len);
-      memcpy (&savedbuf[c], mergegrp->gr_mem[i], len);
-      members[savedmemcount + i] = &savedbuf[c];
-      c += len;
-    }
-  /* Add the NULL-terminator.  */
-  members[savedmemcount + memcount] = NULL;
-
-  /* Align for pointers.  We can't simply align C because we need to
-     align savedbuf[c].  */
-  if ((((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1)) != 0)
-    {
-      uintptr_t mis_align = ((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1);
-      c += __alignof__(char **) - mis_align;
-    }
-
-  /* Copy the member array back into the buffer after the member list and free
-     the member array.  */
-  savedgrp->gr_mem = (char **) &savedbuf[c];
-  len = sizeof (char *) * membersize;
-  BUFCHECK (len);
-  memcpy (&savedbuf[c], members, len);
-  c += len;
-
-  free (members);
-  members = NULL;
-
-  /* Finally, copy the results back into mergebuf, since that's the buffer
-     that we were provided by the caller.  */
-  return __copy_grp (*savedgrp, buflen, mergegrp, mergebuf, NULL);
-}
-libc_hidden_def (__merge_grp)
diff --git a/nss/grp-merge.h b/nss/grp-merge.h
deleted file mode 100644
index ba985c556e..0000000000
--- a/nss/grp-merge.h
+++ /dev/null
@@ -1,35 +0,0 @@ 
-/* Group merging implementation.
-   Copyright (C) 2016-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 _GRP_MERGE_H
-#define _GRP_MERGE_H 1
-
-#include <grp.h>
-
-/* Duplicate a grp struct (and its members). When no longer needed, the
-   calling function must free(newbuf).  */
-int
-__copy_grp (const struct group srcgrp, const size_t buflen,
-	    struct group *destgrp, char *destbuf, char **endptr);
-
-/* Merge the member lists of two grp structs together.  */
-int
-__merge_grp (struct group *savedgrp, char *savedbuf, char *savedend,
-	     size_t buflen, struct group *mergegrp, char *mergebuf);
-
-#endif /* _GRP_MERGE_H */