|
|
|
commit 0897c551c0a098020f145885de06a5c10e5cc96b
|
|
|
|
Author: Carlos O'Donell <carlos@systemhalted.org>
|
|
|
|
Date: Wed Jan 21 10:08:18 2015 -0500
|
|
|
|
|
|
|
|
tst-getpw: Rewrite.
|
|
|
|
|
|
|
|
The test is rewritten to look for the testable conditions and
|
|
|
|
exit once they are all detected. This prevents the test from
|
|
|
|
iterating over 2000 UIDs and looking up each one. It speeds up
|
|
|
|
the test and prevents it from failing if the system under test
|
|
|
|
has an NSS-based passwd that is slower than the test timeout.
|
|
|
|
|
|
|
|
See:
|
|
|
|
https://sourceware.org/ml/libc-alpha/2015-01/msg00394.html
|
|
|
|
|
|
|
|
diff --git a/pwd/tst-getpw.c b/pwd/tst-getpw.c
|
|
|
|
index 059c9e0..e3e101b 100644
|
|
|
|
--- a/pwd/tst-getpw.c
|
|
|
|
+++ b/pwd/tst-getpw.c
|
|
|
|
@@ -1,4 +1,4 @@
|
|
|
|
-/* Copyright (C) 1999 Free Software Foundation, Inc.
|
|
|
|
+/* Copyright (C) 1999-2016 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
|
|
|
|
@@ -15,26 +15,100 @@
|
|
|
|
License along with the GNU C Library; if not, see
|
|
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
|
|
|
|
+#include <stdio.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
+#include <errno.h>
|
|
|
|
+#include <stdbool.h>
|
|
|
|
+
|
|
|
|
+/* We want to test getpw by calling it with a uid that does
|
|
|
|
+ exist and one that doesn't exist. We track if we've met those
|
|
|
|
+ conditions and exit. We also track if we've failed due to lack
|
|
|
|
+ of memory. That constitutes all of the standard failure cases. */
|
|
|
|
+bool seen_hit;
|
|
|
|
+bool seen_miss;
|
|
|
|
+bool seen_oom;
|
|
|
|
+
|
|
|
|
+/* How many errors we've had while running the test. */
|
|
|
|
+int errors;
|
|
|
|
|
|
|
|
static void
|
|
|
|
check (uid_t uid)
|
|
|
|
{
|
|
|
|
+ int ret;
|
|
|
|
char buf[1024];
|
|
|
|
|
|
|
|
- (void) getpw (uid, buf);
|
|
|
|
+ ret = getpw (uid, buf);
|
|
|
|
+
|
|
|
|
+ /* Successfully read a password line. */
|
|
|
|
+ if (ret == 0 && !seen_hit)
|
|
|
|
+ {
|
|
|
|
+ printf ("PASS: Read a password line given a uid.\n");
|
|
|
|
+ seen_hit = true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Failed to read a password line. Why? */
|
|
|
|
+ if (ret == -1)
|
|
|
|
+ {
|
|
|
|
+ /* No entry? Technically the errno could be any number
|
|
|
|
+ of values including ESRCH, EBADP or EPERM depending
|
|
|
|
+ on the quality of the nss module that implements the
|
|
|
|
+ underlying lookup. It should be 0 for getpw.*/
|
|
|
|
+ if (errno == 0 && !seen_miss)
|
|
|
|
+ {
|
|
|
|
+ printf ("PASS: Found an invalid uid.\n");
|
|
|
|
+ seen_miss = true;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Out of memory? */
|
|
|
|
+ if (errno == ENOMEM && !seen_oom)
|
|
|
|
+ {
|
|
|
|
+ printf ("FAIL: Failed with ENOMEM.\n");
|
|
|
|
+ seen_oom = true;
|
|
|
|
+ errors++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* We don't expect any other values for errno. */
|
|
|
|
+ if (errno != ENOMEM && errno != 0)
|
|
|
|
+ errors++;
|
|
|
|
+ }
|
|
|
|
}
|
|
|
|
|
|
|
|
-int
|
|
|
|
-main (void)
|
|
|
|
+static int
|
|
|
|
+do_test (void)
|
|
|
|
{
|
|
|
|
+ int ret;
|
|
|
|
uid_t uid;
|
|
|
|
|
|
|
|
- /* Just call it a different number of times the range should be
|
|
|
|
- large enough to find some existing and some non existing uids. */
|
|
|
|
+ /* Should return -1 and set errnot to EINVAL. */
|
|
|
|
+ ret = getpw (0, NULL);
|
|
|
|
+ if (ret == -1 && errno == EINVAL)
|
|
|
|
+ {
|
|
|
|
+ printf ("PASS: NULL buffer returns -1 and sets errno to EINVAL.\n");
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ printf ("FAIL: NULL buffer did not return -1 or set errno to EINVAL.\n");
|
|
|
|
+ errors++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Look for one matching uid, one non-found uid and then stop.
|
|
|
|
+ Set an upper limit at the 16-bit UID mark; no need to go farther. */
|
|
|
|
+ for (uid = 0; uid < ((uid_t) 65535); ++uid)
|
|
|
|
+ {
|
|
|
|
+ check (uid);
|
|
|
|
+ if (seen_miss && seen_hit)
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- for (uid = 0; uid < 2000; ++uid)
|
|
|
|
- check (uid);
|
|
|
|
+ if (!seen_hit)
|
|
|
|
+ printf ("FAIL: Did not read even one password line given a uid.\n");
|
|
|
|
|
|
|
|
- return 0;
|
|
|
|
+ if (!seen_miss)
|
|
|
|
+ printf ("FAIL: Did not find even one invalid uid.\n");
|
|
|
|
+
|
|
|
|
+ return errors;
|
|
|
|
}
|
|
|
|
+
|
|
|
|
+#define TEST_FUNCTION do_test ()
|
|
|
|
+#include "../test-skeleton.c"
|
|
|
|
License along with the GNU C Library; if not, see
|
|
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
|
|
|
|
+#include <stdio.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
+#include <errno.h>
|
|
|
|
+#include <stdbool.h>
|
|
|
|
+
|
|
|
|
+/* We want to test getpw by calling it with a uid that does
|
|
|
|
+ exist and one that doesn't exist. We track if we've met those
|
|
|
|
+ conditions and exit. We also track if we've failed due to lack
|
|
|
|
+ of memory. That constitutes all of the standard failure cases. */
|
|
|
|
+bool seen_hit;
|
|
|
|
+bool seen_miss;
|
|
|
|
+bool seen_oom;
|
|
|
|
+
|
|
|
|
+/* How many errors we've had while running the test. */
|
|
|
|
+int errors;
|
|
|
|
|
|
|
|
static void
|
|
|
|
check (uid_t uid)
|
|
|
|
{
|
|
|
|
+ int ret;
|
|
|
|
char buf[1024];
|
|
|
|
|
|
|
|
- (void) getpw (uid, buf);
|
|
|
|
+ ret = getpw (uid, buf);
|
|
|
|
+
|
|
|
|
+ /* Successfully read a password line. */
|
|
|
|
+ if (ret == 0 && !seen_hit)
|
|
|
|
+ {
|
|
|
|
+ printf ("PASS: Read a password line given a uid.\n");
|
|
|
|
+ seen_hit = true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Failed to read a password line. Why? */
|
|
|
|
+ if (ret == -1)
|
|
|
|
+ {
|
|
|
|
+ /* No entry? Technically the errno could be any number
|
|
|
|
+ of values including ESRCH, EBADP or EPERM depending
|
|
|
|
+ on the quality of the nss module that implements the
|
|
|
|
+ underlying lookup. It should be 0 for getpw.*/
|
|
|
|
+ if (errno == 0 && !seen_miss)
|
|
|
|
+ {
|
|
|
|
+ printf ("PASS: Found an invalid uid.\n");
|
|
|
|
+ seen_miss = true;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Out of memory? */
|
|
|
|
+ if (errno == ENOMEM && !seen_oom)
|
|
|
|
+ {
|
|
|
|
+ printf ("FAIL: Failed with ENOMEM.\n");
|
|
|
|
+ seen_oom = true;
|
|
|
|
+ errors++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* We don't expect any other values for errno. */
|
|
|
|
+ if (errno != ENOMEM && errno != 0)
|
|
|
|
+ errors++;
|
|
|
|
+ }
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
do_test (void)
|
|
|
|
{
|
|
|
|
+ int ret;
|
|
|
|
uid_t uid;
|
|
|
|
|
|
|
|
- /* Just call it a different number of times the range should be
|
|
|
|
- large enough to find some existing and some non existing uids. */
|
|
|
|
+ /* Should return -1 and set errnot to EINVAL. */
|
|
|
|
+ ret = getpw (0, NULL);
|
|
|
|
+ if (ret == -1 && errno == EINVAL)
|
|
|
|
+ {
|
|
|
|
+ printf ("PASS: NULL buffer returns -1 and sets errno to EINVAL.\n");
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ printf ("FAIL: NULL buffer did not return -1 or set errno to EINVAL.\n");
|
|
|
|
+ errors++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Look for one matching uid, one non-found uid and then stop.
|
|
|
|
+ Set an upper limit at the 16-bit UID mark; no need to go farther. */
|
|
|
|
+ for (uid = 0; uid < ((uid_t) 65535); ++uid)
|
|
|
|
+ {
|
|
|
|
+ check (uid);
|
|
|
|
+ if (seen_miss && seen_hit)
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!seen_hit)
|
|
|
|
+ printf ("FAIL: Did not read even one password line given a uid.\n");
|
|
|
|
|
|
|
|
- for (uid = 0; uid < 2000; ++uid)
|
|
|
|
- check (uid);
|
|
|
|
+ if (!seen_miss)
|
|
|
|
+ printf ("FAIL: Did not find even one invalid uid.\n");
|
|
|
|
|
|
|
|
- return 0;
|
|
|
|
+ return errors;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define TEST_FUNCTION do_test ()
|