c41d59
commit 969e9733c7d17edf1e239a73fa172f357561f440
c41d59
Author: Florian Weimer <fweimer@redhat.com>
c41d59
Date:   Tue Feb 21 09:20:28 2023 +0100
c41d59
c41d59
    gshadow: Matching sgetsgent, sgetsgent_r ERANGE handling (bug 30151)
c41d59
    
c41d59
    Before this change, sgetsgent_r did not set errno to ERANGE, but
c41d59
    sgetsgent only check errno, not the return value from sgetsgent_r.
c41d59
    Consequently, sgetsgent did not detect any error, and reported
c41d59
    success to the caller, without initializing the struct sgrp object
c41d59
    whose address was returned.
c41d59
    
c41d59
    This commit changes sgetsgent_r to set errno as well.  This avoids
c41d59
    similar issues in applications which only change errno.
c41d59
    
c41d59
    Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
c41d59
c41d59
diff --git a/gshadow/Makefile b/gshadow/Makefile
c41d59
index 796fbbf473..a95524593a 100644
c41d59
--- a/gshadow/Makefile
c41d59
+++ b/gshadow/Makefile
c41d59
@@ -26,7 +26,7 @@ headers		= gshadow.h
c41d59
 routines	= getsgent getsgnam sgetsgent fgetsgent putsgent \
c41d59
 		  getsgent_r getsgnam_r sgetsgent_r fgetsgent_r
c41d59
 
c41d59
-tests = tst-gshadow tst-putsgent tst-fgetsgent_r
c41d59
+tests = tst-gshadow tst-putsgent tst-fgetsgent_r tst-sgetsgent
c41d59
 
c41d59
 CFLAGS-getsgent_r.c += -fexceptions
c41d59
 CFLAGS-getsgent.c += -fexceptions
c41d59
diff --git a/gshadow/sgetsgent_r.c b/gshadow/sgetsgent_r.c
c41d59
index ea085e91d7..c75624e1f7 100644
c41d59
--- a/gshadow/sgetsgent_r.c
c41d59
+++ b/gshadow/sgetsgent_r.c
c41d59
@@ -61,7 +61,10 @@ __sgetsgent_r (const char *string, struct sgrp *resbuf, char *buffer,
c41d59
       buffer[buflen - 1] = '\0';
c41d59
       sp = strncpy (buffer, string, buflen);
c41d59
       if (buffer[buflen - 1] != '\0')
c41d59
-	return ERANGE;
c41d59
+	{
c41d59
+	  __set_errno (ERANGE);
c41d59
+	  return ERANGE;
c41d59
+	}
c41d59
     }
c41d59
   else
c41d59
     sp = (char *) string;
c41d59
diff --git a/gshadow/tst-sgetsgent.c b/gshadow/tst-sgetsgent.c
c41d59
new file mode 100644
c41d59
index 0000000000..0370c10fd0
c41d59
--- /dev/null
c41d59
+++ b/gshadow/tst-sgetsgent.c
c41d59
@@ -0,0 +1,69 @@
c41d59
+/* Test large input for sgetsgent (bug 30151).
c41d59
+   Copyright (C) 2023 Free Software Foundation, Inc.
c41d59
+   This file is part of the GNU C Library.
c41d59
+
c41d59
+   The GNU C Library is free software; you can redistribute it and/or
c41d59
+   modify it under the terms of the GNU Lesser General Public
c41d59
+   License as published by the Free Software Foundation; either
c41d59
+   version 2.1 of the License, or (at your option) any later version.
c41d59
+
c41d59
+   The GNU C Library is distributed in the hope that it will be useful,
c41d59
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
c41d59
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
c41d59
+   Lesser General Public License for more details.
c41d59
+
c41d59
+   You should have received a copy of the GNU Lesser General Public
c41d59
+   License along with the GNU C Library; if not, see
c41d59
+   <https://www.gnu.org/licenses/>.  */
c41d59
+
c41d59
+#include <gshadow.h>
c41d59
+#include <stddef.h>
c41d59
+#include <support/check.h>
c41d59
+#include <support/support.h>
c41d59
+#include <support/xmemstream.h>
c41d59
+#include <stdlib.h>
c41d59
+
c41d59
+static int
c41d59
+do_test (void)
c41d59
+{
c41d59
+  /* Create a shadow group with 1000 members.  */
c41d59
+  struct xmemstream mem;
c41d59
+  xopen_memstream (&mem;;
c41d59
+  const char *passwd = "k+zD0nucwfxAo3sw1NXUj6K5vt5M16+X0TVGdE1uFvq5R8V7efJ";
c41d59
+  fprintf (mem.out, "group-name:%s::m0", passwd);
c41d59
+  for (int i = 1; i < 1000; ++i)
c41d59
+    fprintf (mem.out, ",m%d", i);
c41d59
+  xfclose_memstream (&mem;;
c41d59
+
c41d59
+  /* Call sgetsgent.  */
c41d59
+  char *input = mem.buffer;
c41d59
+  struct sgrp *e = sgetsgent (input);
c41d59
+  TEST_VERIFY_EXIT (e != NULL);
c41d59
+  TEST_COMPARE_STRING (e->sg_namp, "group-name");
c41d59
+  TEST_COMPARE_STRING (e->sg_passwd, passwd);
c41d59
+  /* No administrators.  */
c41d59
+  TEST_COMPARE_STRING (e->sg_adm[0], NULL);
c41d59
+  /* Check the members list.  */
c41d59
+  for (int i = 0; i < 1000; ++i)
c41d59
+    {
c41d59
+      char *member = xasprintf ("m%d", i);
c41d59
+      TEST_COMPARE_STRING (e->sg_mem[i], member);
c41d59
+      free (member);
c41d59
+    }
c41d59
+  TEST_COMPARE_STRING (e->sg_mem[1000], NULL);
c41d59
+
c41d59
+  /* Check that putsgent brings back the input string.  */
c41d59
+  xopen_memstream (&mem;;
c41d59
+  TEST_COMPARE (putsgent (e, mem.out), 0);
c41d59
+  xfclose_memstream (&mem;;
c41d59
+  /* Compare without the trailing '\n' that putsgent added.  */
c41d59
+  TEST_COMPARE (mem.buffer[mem.length - 1], '\n');
c41d59
+  mem.buffer[mem.length - 1] = '\0';
c41d59
+  TEST_COMPARE_STRING (mem.buffer, input);
c41d59
+
c41d59
+  free (mem.buffer);
c41d59
+  free (input);
c41d59
+  return 0;
c41d59
+}
c41d59
+
c41d59
+#include <support/test-driver.c>