Blame SOURCES/glibc-rh1298975.patch

147e83
commit ced8f8933673f4efda1d666d26a1a949602035ed
147e83
Author: Stephen Gallagher <sgallagh@redhat.com>
147e83
Date:   Fri Apr 29 22:11:09 2016 -0400
147e83
147e83
    NSS: Implement group merging support.
147e83
147e83
commit 2413e73c32fc36470885ae548631e081d66f4201
147e83
Author: Zack Weinberg <zackw@panix.com>
147e83
Date:   Mon Jul 18 09:33:21 2016 -0300
147e83
147e83
    Don't install the internal header grp-merge.h
147e83
147e83
--- glibc-2.17-c758a686/grp/Makefile
147e83
+++ glibc-2.17-c758a686/grp/Makefile
147e83
@@ -23,7 +23,8 @@
147e83
 
147e83
 routines := fgetgrent initgroups setgroups \
147e83
 	    getgrent getgrgid getgrnam putgrent \
147e83
-	    getgrent_r getgrgid_r getgrnam_r fgetgrent_r
147e83
+	    getgrent_r getgrgid_r getgrnam_r fgetgrent_r \
147e83
+	    grp-merge
147e83
 
147e83
 include ../Makeconfig
147e83
 
147e83
--- glibc-2.17-c758a686/grp/Versions
147e83
+++ glibc-2.17-c758a686/grp/Versions
147e83
@@ -28,4 +28,7 @@
147e83
     # g*
147e83
     getgrouplist;
147e83
   }
147e83
+  GLIBC_PRIVATE {
147e83
+    __merge_grp; __copy_grp;
147e83
+  }
147e83
 }
147e83
--- glibc-2.17-c758a686/grp/getgrgid_r.c
147e83
+++ glibc-2.17-c758a686/grp/getgrgid_r.c
147e83
@@ -18,6 +18,7 @@
147e83
 
147e83
 #include <grp.h>
147e83
 
147e83
+#include <grp-merge.h>
147e83
 
147e83
 #define LOOKUP_TYPE	struct group
147e83
 #define FUNCTION_NAME	getgrgid
147e83
@@ -25,5 +26,7 @@
147e83
 #define ADD_PARAMS	gid_t gid
147e83
 #define ADD_VARIABLES	gid
147e83
 #define BUFLEN		NSS_BUFLEN_GROUP
147e83
+#define DEEPCOPY_FN	__copy_grp
147e83
+#define MERGE_FN	__merge_grp
147e83
 
147e83
 #include <nss/getXXbyYY_r.c>
147e83
--- glibc-2.17-c758a686/grp/getgrnam_r.c
147e83
+++ glibc-2.17-c758a686/grp/getgrnam_r.c
147e83
@@ -18,6 +18,7 @@
147e83
 
147e83
 #include <grp.h>
147e83
 
147e83
+#include <grp-merge.h>
147e83
 
147e83
 #define LOOKUP_TYPE	struct group
147e83
 #define FUNCTION_NAME	getgrnam
147e83
@@ -25,4 +26,7 @@
147e83
 #define ADD_PARAMS	const char *name
147e83
 #define ADD_VARIABLES	name
147e83
 
147e83
+#define DEEPCOPY_FN	__copy_grp
147e83
+#define MERGE_FN	__merge_grp
147e83
+
147e83
 #include <nss/getXXbyYY_r.c>
147e83
--- glibc-2.17-c758a686/grp/grp-merge.c
147e83
+++ glibc-2.17-c758a686/grp/grp-merge.c
147e83
@@ -0,0 +1,186 @@
147e83
+/* Group merging implementation.
147e83
+   Copyright (C) 2016 Free Software Foundation, Inc.
147e83
+   This file is part of the GNU C Library.
147e83
+
147e83
+   The GNU C Library is free software; you can redistribute it and/or
147e83
+   modify it under the terms of the GNU Lesser General Public
147e83
+   License as published by the Free Software Foundation; either
147e83
+   version 2.1 of the License, or (at your option) any later version.
147e83
+
147e83
+   The GNU C Library is distributed in the hope that it will be useful,
147e83
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
147e83
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
147e83
+   Lesser General Public License for more details.
147e83
+
147e83
+   You should have received a copy of the GNU Lesser General Public
147e83
+   License along with the GNU C Library; if not, see
147e83
+   <http://www.gnu.org/licenses/>.  */
147e83
+
147e83
+#include <errno.h>
147e83
+#include <stdlib.h>
147e83
+#include <string.h>
147e83
+#include <grp.h>
147e83
+#include <grp-merge.h>
147e83
+
147e83
+#define BUFCHECK(size)			\
147e83
+  ({					\
147e83
+    do					\
147e83
+      {					\
147e83
+	if (c + (size) > buflen)	\
147e83
+          {				\
147e83
+	    free (members);		\
147e83
+	    return ERANGE;		\
147e83
+	  }				\
147e83
+      }					\
147e83
+    while (0);				\
147e83
+  })
147e83
+
147e83
+int
147e83
+internal_function
147e83
+__copy_grp (const struct group srcgrp, const size_t buflen,
147e83
+	    struct group *destgrp, char *destbuf, char **endptr)
147e83
+{
147e83
+  size_t i;
147e83
+  size_t c = 0;
147e83
+  size_t len;
147e83
+  size_t memcount;
147e83
+  char **members = NULL;
147e83
+
147e83
+  /* Copy the GID.  */
147e83
+  destgrp->gr_gid = srcgrp.gr_gid;
147e83
+
147e83
+  /* Copy the name.  */
147e83
+  len = strlen (srcgrp.gr_name) + 1;
147e83
+  BUFCHECK (len);
147e83
+  memcpy (&destbuf[c], srcgrp.gr_name, len);
147e83
+  destgrp->gr_name = &destbuf[c];
147e83
+  c += len;
147e83
+
147e83
+  /* Copy the password.  */
147e83
+  len = strlen (srcgrp.gr_passwd) + 1;
147e83
+  BUFCHECK (len);
147e83
+  memcpy (&destbuf[c], srcgrp.gr_passwd, len);
147e83
+  destgrp->gr_passwd = &destbuf[c];
147e83
+  c += len;
147e83
+
147e83
+  /* Count all of the members.  */
147e83
+  for (memcount = 0; srcgrp.gr_mem[memcount]; memcount++)
147e83
+    ;
147e83
+
147e83
+  /* Allocate a temporary holding area for the pointers to the member
147e83
+     contents, including space for a NULL-terminator.  */
147e83
+  members = malloc (sizeof (char *) * (memcount + 1));
147e83
+  if (members == NULL)
147e83
+    return ENOMEM;
147e83
+
147e83
+  /* Copy all of the group members to destbuf and add a pointer to each of
147e83
+     them into the 'members' array.  */
147e83
+  for (i = 0; srcgrp.gr_mem[i]; i++)
147e83
+    {
147e83
+      len = strlen (srcgrp.gr_mem[i]) + 1;
147e83
+      BUFCHECK (len);
147e83
+      memcpy (&destbuf[c], srcgrp.gr_mem[i], len);
147e83
+      members[i] = &destbuf[c];
147e83
+      c += len;
147e83
+    }
147e83
+  members[i] = NULL;
147e83
+
147e83
+  /* Copy the pointers from the members array into the buffer and assign them
147e83
+     to the gr_mem member of destgrp.  */
147e83
+  destgrp->gr_mem = (char **) &destbuf[c];
147e83
+  len = sizeof (char *) * (memcount + 1);
147e83
+  BUFCHECK (len);
147e83
+  memcpy (&destbuf[c], members, len);
147e83
+  c += len;
147e83
+  free (members);
147e83
+  members = NULL;
147e83
+
147e83
+  /* Save the count of members at the end.  */
147e83
+  BUFCHECK (sizeof (size_t));
147e83
+  memcpy (&destbuf[c], &memcount, sizeof (size_t));
147e83
+  c += sizeof (size_t);
147e83
+
147e83
+  if (endptr)
147e83
+    *endptr = destbuf + c;
147e83
+  return 0;
147e83
+}
147e83
+libc_hidden_def (__copy_grp)
147e83
+
147e83
+/* Check that the name, GID and passwd fields match, then
147e83
+   copy in the gr_mem array.  */
147e83
+int
147e83
+internal_function
147e83
+__merge_grp (struct group *savedgrp, char *savedbuf, char *savedend,
147e83
+	     size_t buflen, struct group *mergegrp, char *mergebuf)
147e83
+{
147e83
+  size_t c, i, len;
147e83
+  size_t savedmemcount;
147e83
+  size_t memcount;
147e83
+  size_t membersize;
147e83
+  char **members = NULL;
147e83
+
147e83
+  /* We only support merging members of groups with identical names and
147e83
+     GID values. If we hit this case, we need to overwrite the current
147e83
+     buffer with the saved one (which is functionally equivalent to
147e83
+     treating the new lookup as NSS_STATUS_NOTFOUND).  */
147e83
+  if (mergegrp->gr_gid != savedgrp->gr_gid
147e83
+      || strcmp (mergegrp->gr_name, savedgrp->gr_name))
147e83
+    return __copy_grp (*savedgrp, buflen, mergegrp, mergebuf, NULL);
147e83
+
147e83
+  /* Get the count of group members from the last sizeof (size_t) bytes in the
147e83
+     mergegrp buffer.  */
147e83
+  savedmemcount = (size_t) *(savedend - sizeof (size_t));
147e83
+
147e83
+  /* Get the count of new members to add.  */
147e83
+  for (memcount = 0; mergegrp->gr_mem[memcount]; memcount++)
147e83
+    ;
147e83
+
147e83
+  /* Create a temporary array to hold the pointers to the member values from
147e83
+     both the saved and merge groups.  */
147e83
+  membersize = savedmemcount + memcount + 1;
147e83
+  members = malloc (sizeof (char *) * membersize);
147e83
+  if (members == NULL)
147e83
+    return ENOMEM;
147e83
+
147e83
+  /* Copy in the existing member pointers from the saved group
147e83
+     Note: this is not NULL-terminated yet.  */
147e83
+  memcpy (members, savedgrp->gr_mem, sizeof (char *) * savedmemcount);
147e83
+
147e83
+  /* Back up into the savedbuf until we get back to the NULL-terminator of the
147e83
+     group member list. (This means walking back savedmemcount + 1 (char *) pointers
147e83
+     and the member count value.
147e83
+     The value of c is going to be the used length of the buffer backed up by
147e83
+     the member count and further backed up by the size of the pointers.  */
147e83
+  c = savedend - savedbuf
147e83
+      - sizeof (size_t)
147e83
+      - sizeof (char *) * (savedmemcount + 1);
147e83
+
147e83
+  /* Add all the new group members, overwriting the old NULL-terminator while
147e83
+     adding the new pointers to the temporary array.  */
147e83
+  for (i = 0; mergegrp->gr_mem[i]; i++)
147e83
+    {
147e83
+      len = strlen (mergegrp->gr_mem[i]) + 1;
147e83
+      BUFCHECK (len);
147e83
+      memcpy (&savedbuf[c], mergegrp->gr_mem[i], len);
147e83
+      members[savedmemcount + i] = &savedbuf[c];
147e83
+      c += len;
147e83
+    }
147e83
+  /* Add the NULL-terminator.  */
147e83
+  members[savedmemcount + memcount] = NULL;
147e83
+
147e83
+  /* Copy the member array back into the buffer after the member list and free
147e83
+     the member array.  */
147e83
+  savedgrp->gr_mem = (char **) &savedbuf[c];
147e83
+  len = sizeof (char *) * membersize;
147e83
+  BUFCHECK (len);
147e83
+  memcpy (&savedbuf[c], members, len);
147e83
+  c += len;
147e83
+
147e83
+  free (members);
147e83
+  members = NULL;
147e83
+
147e83
+  /* Finally, copy the results back into mergebuf, since that's the buffer
147e83
+     that we were provided by the caller.  */
147e83
+  return __copy_grp (*savedgrp, buflen, mergegrp, mergebuf, NULL);
147e83
+}
147e83
+libc_hidden_def (__merge_grp)
147e83
--- glibc-2.17-c758a686/grp/grp-merge.h
147e83
+++ glibc-2.17-c758a686/grp/grp-merge.h
147e83
@@ -0,0 +1,37 @@
147e83
+/* Group merging implementation.
147e83
+   Copyright (C) 2016 Free Software Foundation, Inc.
147e83
+   This file is part of the GNU C Library.
147e83
+
147e83
+   The GNU C Library is free software; you can redistribute it and/or
147e83
+   modify it under the terms of the GNU Lesser General Public
147e83
+   License as published by the Free Software Foundation; either
147e83
+   version 2.1 of the License, or (at your option) any later version.
147e83
+
147e83
+   The GNU C Library is distributed in the hope that it will be useful,
147e83
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
147e83
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
147e83
+   Lesser General Public License for more details.
147e83
+
147e83
+   You should have received a copy of the GNU Lesser General Public
147e83
+   License along with the GNU C Library; if not, see
147e83
+   <http://www.gnu.org/licenses/>.  */
147e83
+
147e83
+#ifndef _GRP_MERGE_H
147e83
+#define _GRP_MERGE_H 1
147e83
+
147e83
+#include <grp.h>
147e83
+
147e83
+/* Duplicate a grp struct (and its members). When no longer needed, the
147e83
+   calling function must free(newbuf).  */
147e83
+int
147e83
+__copy_grp (const struct group srcgrp, const size_t buflen,
147e83
+	    struct group *destgrp, char *destbuf, char **endptr)
147e83
+	    internal_function;
147e83
+
147e83
+/* Merge the member lists of two grp structs together.  */
147e83
+int
147e83
+__merge_grp (struct group *savedgrp, char *savedbuf, char *savedend,
147e83
+	     size_t buflen, struct group *mergegrp, char *mergebuf)
147e83
+	     internal_function;
147e83
+
147e83
+#endif /* _GRP_MERGE_H */
147e83
--- glibc-2.17-c758a686/include/grp-merge.h
147e83
+++ glibc-2.17-c758a686/include/grp-merge.h
147e83
@@ -0,0 +1,7 @@
147e83
+#ifndef _GRP_MERGE_H
147e83
+#include <grp/grp-merge.h>
147e83
+
147e83
+libc_hidden_proto (__copy_grp)
147e83
+libc_hidden_proto (__merge_grp)
147e83
+
147e83
+#endif /* _GRP_MERGE_H */
147e83
--- glibc-2.17-c758a686/manual/nss.texi
147e83
+++ glibc-2.17-c758a686/manual/nss.texi
147e83
@@ -180,7 +180,7 @@
147e83
 
147e83
 The case of the keywords is insignificant.  The @var{status}
147e83
 values are the results of a call to a lookup function of a specific
147e83
-service.  They mean
147e83
+service.  They mean:
147e83
 
147e83
 @ftable @samp
147e83
 @item success
147e83
@@ -204,6 +204,50 @@
147e83
 @end ftable
147e83
 
147e83
 @noindent
147e83
+The @var{action} values mean:
147e83
+
147e83
+@ftable @samp
147e83
+@item return
147e83
+
147e83
+If the status matches, stop the lookup process at this service
147e83
+specification.  If an entry is available, provide it to the application.
147e83
+If an error occurred, report it to the application.  In case of a prior
147e83
+@samp{merge} action, the data is combined with previous lookup results,
147e83
+as explained below.
147e83
+
147e83
+@item continue
147e83
+
147e83
+If the status matches, proceed with the lookup process at the next
147e83
+entry, discarding the result of the current lookup (and any merged
147e83
+data).  An exception is the @samp{initgroups} database and the
147e83
+@samp{success} status, where @samp{continue} acts like @code{merge}
147e83
+below.
147e83
+
147e83
+@item merge
147e83
+
147e83
+Proceed with the lookup process, retaining the current lookup result.
147e83
+This action is useful only with the @samp{success} status.  If a
147e83
+subsequent service lookup succeeds and has a matching @samp{return}
147e83
+specification, the results are merged, the lookup process ends, and the
147e83
+merged results are returned to the application.  If the following service
147e83
+has a matching @samp{merge} action, the lookup process continues,
147e83
+retaining the combined data from this and any previous lookups.
147e83
+
147e83
+After a @code{merge} action, errors from subsequent lookups are ignored,
147e83
+and the data gathered so far will be returned.
147e83
+
147e83
+The @samp{merge} only applies to the @samp{success} status.  It is
147e83
+currently implemented for the @samp{group} database and its group
147e83
+members field, @samp{gr_mem}.  If specified for other databases, it
147e83
+causes the lookup to fail (if the @var{status} matches).
147e83
+
147e83
+When processing @samp{merge} for @samp{group} membership, the group GID
147e83
+and name must be identical for both entries.  If only one or the other is
147e83
+a match, the behavior is undefined.
147e83
+
147e83
+@end ftable
147e83
+
147e83
+@noindent
147e83
 If we have a line like
147e83
 
147e83
 @smallexample
147e83
--- glibc-2.17-c758a686/nscd/getgrgid_r.c
147e83
+++ glibc-2.17-c758a686/nscd/getgrgid_r.c
147e83
@@ -17,6 +17,7 @@
147e83
 
147e83
 #include <grp.h>
147e83
 
147e83
+#include <grp-merge.h>
147e83
 
147e83
 #define LOOKUP_TYPE	struct group
147e83
 #define FUNCTION_NAME	getgrgid
147e83
@@ -25,6 +26,9 @@
147e83
 #define ADD_VARIABLES	gid
147e83
 #define BUFLEN		NSS_BUFLEN_GROUP
147e83
 
147e83
+#define DEEPCOPY_FN	__copy_grp
147e83
+#define MERGE_FN	__merge_grp
147e83
+
147e83
 /* We are nscd, so we don't want to be talking to ourselves.  */
147e83
 #undef	USE_NSCD
147e83
 
147e83
--- glibc-2.17-c758a686/nscd/getgrnam_r.c
147e83
+++ glibc-2.17-c758a686/nscd/getgrnam_r.c
147e83
@@ -17,6 +17,7 @@
147e83
 
147e83
 #include <grp.h>
147e83
 
147e83
+#include <grp-merge.h>
147e83
 
147e83
 #define LOOKUP_TYPE	struct group
147e83
 #define FUNCTION_NAME	getgrnam
147e83
@@ -24,6 +25,9 @@
147e83
 #define ADD_PARAMS	const char *name
147e83
 #define ADD_VARIABLES	name
147e83
 
147e83
+#define DEEPCOPY_FN	__copy_grp
147e83
+#define MERGE_FN	__merge_grp
147e83
+
147e83
 /* We are nscd, so we don't want to be talking to ourselves.  */
147e83
 #undef	USE_NSCD
147e83
 
147e83
--- glibc-2.17-c758a686/nss/getXXbyYY_r.c
147e83
+++ glibc-2.17-c758a686/nss/getXXbyYY_r.c
147e83
@@ -131,6 +131,52 @@
147e83
 # define AF_VAL AF_INET
147e83
 #endif
147e83
 
147e83
+
147e83
+/* Set defaults for merge functions that haven't been defined.  */
147e83
+#ifndef DEEPCOPY_FN
147e83
+static inline int
147e83
+__copy_einval (LOOKUP_TYPE a,
147e83
+	       const size_t b,
147e83
+	       LOOKUP_TYPE *c,
147e83
+	       char *d,
147e83
+	       char **e)
147e83
+{
147e83
+  return EINVAL;
147e83
+}
147e83
+# define DEEPCOPY_FN __copy_einval
147e83
+#endif
147e83
+
147e83
+#ifndef MERGE_FN
147e83
+static inline int
147e83
+__merge_einval (LOOKUP_TYPE *a,
147e83
+		char *b,
147e83
+		char *c,
147e83
+		size_t d,
147e83
+		LOOKUP_TYPE *e,
147e83
+		char *f)
147e83
+{
147e83
+  return EINVAL;
147e83
+}
147e83
+# define MERGE_FN __merge_einval
147e83
+#endif
147e83
+
147e83
+#define CHECK_MERGE(err, status)		\
147e83
+  ({						\
147e83
+    do						\
147e83
+      {						\
147e83
+	if (err)				\
147e83
+	  {					\
147e83
+	    __set_errno (err);			\
147e83
+	    if (err == ERANGE)			\
147e83
+	      status = NSS_STATUS_TRYAGAIN;	\
147e83
+	    else				\
147e83
+	      status = NSS_STATUS_UNAVAIL;	\
147e83
+	    break;				\
147e83
+	  }					\
147e83
+      }						\
147e83
+    while (0);					\
147e83
+  })
147e83
+
147e83
 /* Type of the lookup function we need here.  */
147e83
 typedef enum nss_status (*lookup_function) (ADD_PARAMS, LOOKUP_TYPE *, char *,
147e83
 					    size_t, int * H_ERRNO_PARM
147e83
@@ -152,13 +198,16 @@
147e83
   static service_user *startp;
147e83
   static lookup_function start_fct;
147e83
   service_user *nip;
147e83
+  int do_merge = 0;
147e83
+  LOOKUP_TYPE mergegrp;
147e83
+  char *mergebuf = NULL;
147e83
+  char *endptr = NULL;
147e83
   union
147e83
   {
147e83
     lookup_function l;
147e83
     void *ptr;
147e83
   } fct;
147e83
-
147e83
-  int no_more;
147e83
+  int no_more, err;
147e83
   enum nss_status status = NSS_STATUS_UNAVAIL;
147e83
 #ifdef USE_NSCD
147e83
   int nscd_status;
147e83
@@ -278,9 +327,66 @@
147e83
 	  && errno == ERANGE)
147e83
 	break;
147e83
 
147e83
+      if (do_merge)
147e83
+	{
147e83
+
147e83
+	  if (status == NSS_STATUS_SUCCESS)
147e83
+	    {
147e83
+	      /* The previous loop saved a buffer for merging.
147e83
+		 Perform the merge now.  */
147e83
+	      err = MERGE_FN (&mergegrp, mergebuf, endptr, buflen, resbuf,
147e83
+			      buffer);
147e83
+	      CHECK_MERGE (err,status);
147e83
+	      do_merge = 0;
147e83
+	    }
147e83
+	  else
147e83
+	    {
147e83
+	      /* If the result wasn't SUCCESS, copy the saved buffer back
147e83
+	         into the result buffer and set the status back to
147e83
+	         NSS_STATUS_SUCCESS to match the previous pass through the
147e83
+	         loop.
147e83
+	          * If the next action is CONTINUE, it will overwrite the value
147e83
+	            currently in the buffer and return the new value.
147e83
+	          * If the next action is RETURN, we'll return the previously-
147e83
+	            acquired values.
147e83
+	          * If the next action is MERGE, then it will be added to the
147e83
+	            buffer saved from the previous source.  */
147e83
+	      err = DEEPCOPY_FN (mergegrp, buflen, resbuf, buffer, NULL);
147e83
+	      CHECK_MERGE (err, status);
147e83
+	      status = NSS_STATUS_SUCCESS;
147e83
+	    }
147e83
+	}
147e83
+
147e83
+      /* If we were are configured to merge this value with the next one,
147e83
+         save the current value of the group struct.  */
147e83
+      if (nss_next_action (nip, status) == NSS_ACTION_MERGE
147e83
+	  && status == NSS_STATUS_SUCCESS)
147e83
+	{
147e83
+	  /* Copy the current values into a buffer to be merged with the next
147e83
+	     set of retrieved values.  */
147e83
+	  if (mergebuf == NULL)
147e83
+	    {
147e83
+	      /* Only allocate once and reuse it for as many merges as we need
147e83
+	         to perform.  */
147e83
+	      mergebuf = malloc (buflen);
147e83
+	      if (mergebuf == NULL)
147e83
+		{
147e83
+		  __set_errno (ENOMEM);
147e83
+		  status = NSS_STATUS_UNAVAIL;
147e83
+		  break;
147e83
+		}
147e83
+	    }
147e83
+
147e83
+	  err = DEEPCOPY_FN (*resbuf, buflen, &mergegrp, mergebuf, &endptr);
147e83
+	  CHECK_MERGE (err, status);
147e83
+	  do_merge = 1;
147e83
+	}
147e83
+
147e83
       no_more = __nss_next2 (&nip, REENTRANT_NAME_STRING,
147e83
 			     REENTRANT2_NAME_STRING, &fct.ptr, status, 0);
147e83
     }
147e83
+  free (mergebuf);
147e83
+  mergebuf = NULL;
147e83
 
147e83
 #ifdef HANDLE_DIGITS_DOTS
147e83
 done:
147e83
--- glibc-2.17-c758a686/nss/getnssent_r.c
147e83
+++ glibc-2.17-c758a686/nss/getnssent_r.c
147e83
@@ -79,7 +79,18 @@
147e83
       else
147e83
 	status = DL_CALL_FCT (fct.f, (0));
147e83
 
147e83
-      no_more = __nss_next2 (nip, func_name, NULL, &fct.ptr, status, 0);
147e83
+
147e83
+      /* This is a special-case.  When [SUCCESS=merge] is in play,
147e83
+         _nss_next2() will skip to the next database.  Due to the
147e83
+         implementation of that function, we can't know whether we're
147e83
+         in an enumeration or an individual lookup, which behaves
147e83
+         differently with regards to merging.  We'll treat SUCCESS as
147e83
+         an indication to start the enumeration at this database. */
147e83
+      if (nss_next_action (*nip, status) == NSS_ACTION_MERGE)
147e83
+	no_more = 1;
147e83
+      else
147e83
+	no_more = __nss_next2 (nip, func_name, NULL, &fct.ptr, status, 0);
147e83
+
147e83
       if (is_last_nip)
147e83
 	*last_nip = *nip;
147e83
     }
147e83
@@ -175,8 +186,18 @@
147e83
 
147e83
       do
147e83
 	{
147e83
-	  no_more = __nss_next2 (nip, getent_func_name, NULL, &fct.ptr,
147e83
-				 status, 0);
147e83
+        /* This is a special-case.  When [SUCCESS=merge] is in play,
147e83
+           _nss_next2() will skip to the next database.  Due to the
147e83
+           implementation of that function, we can't know whether we're
147e83
+           in an enumeration or an individual lookup, which behaves
147e83
+           differently with regards to merging.  We'll treat SUCCESS as
147e83
+           an indication to return the results here. */
147e83
+	  if (status == NSS_STATUS_SUCCESS
147e83
+	      && nss_next_action (*nip, status) == NSS_ACTION_MERGE)
147e83
+	    no_more = 1;
147e83
+	  else
147e83
+	    no_more = __nss_next2 (nip, getent_func_name, NULL, &fct.ptr,
147e83
+				   status, 0);
147e83
 
147e83
 	  if (is_last_nip)
147e83
 	    *last_nip = *nip;
147e83
--- glibc-2.17-c758a686/nss/nsswitch.c
147e83
+++ glibc-2.17-c758a686/nss/nsswitch.c
147e83
@@ -712,6 +712,9 @@
147e83
 	      else if (line - name == 8
147e83
 		       && __strncasecmp (name, "CONTINUE", 8) == 0)
147e83
 		action = NSS_ACTION_CONTINUE;
147e83
+	      else if (line - name == 5
147e83
+		       && __strncasecmp (name, "MERGE", 5) == 0)
147e83
+		action = NSS_ACTION_MERGE;
147e83
 	      else
147e83
 		goto finish;
147e83
 
147e83
--- glibc-2.17-c758a686/nss/nsswitch.h
147e83
+++ glibc-2.17-c758a686/nss/nsswitch.h
147e83
@@ -32,7 +32,8 @@
147e83
 typedef enum
147e83
 {
147e83
   NSS_ACTION_CONTINUE,
147e83
-  NSS_ACTION_RETURN
147e83
+  NSS_ACTION_RETURN,
147e83
+  NSS_ACTION_MERGE
147e83
 } lookup_actions;
147e83
 
147e83