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