456 lines
11 KiB
Diff
456 lines
11 KiB
Diff
From f2feb94748bd3c64ed153461afa51aebbd717821 Mon Sep 17 00:00:00 2001
|
|
From: Jeff Mahoney <jeffm@suse.com>
|
|
Date: Wed, 2 Dec 2015 11:09:51 -0500
|
|
Subject: [PATCH 1/2] test: Add helper library to fake passwd/group files
|
|
References: bsc#953659
|
|
Git-commit: f2feb94748bd3c64ed153461afa51aebbd717821
|
|
|
|
The requirements for testing are currently that the system have several
|
|
users and groups predefined. The chosen users and groups are typically
|
|
found on every system so that's a safe bet. However, tests for the quote
|
|
code may involve more esoteric names that include backslashes or other
|
|
quoted characters. This patch adds a helper library that implements
|
|
the passwd and group calls and redirects the reads to project-defined
|
|
passwd and group files. That way, we know for certain that those
|
|
usernames and groups will be found during testing. The helper library is
|
|
enabled using LD_PRELOAD via a wrapper script. The library will not be
|
|
installed as part of the project's make install. Since the local user
|
|
might not be found in the local test.{group,passwd}, we extend test/run
|
|
to use numeric uid/gids if the lookup fails.
|
|
|
|
Acked-by: Jeff Mahoney <jeffm@suse.com>
|
|
---
|
|
test/Makemodule.am | 11 +++-
|
|
test/run | 17 ++++--
|
|
test/runwrapper | 6 +++
|
|
test/test.group | 3 ++
|
|
test/test.passwd | 5 ++
|
|
test/test_group.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
test/test_passwd.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
7 files changed, 341 insertions(+), 4 deletions(-)
|
|
create mode 100755 test/runwrapper
|
|
create mode 100644 test/test.group
|
|
create mode 100644 test/test.passwd
|
|
create mode 100644 test/test_group.c
|
|
create mode 100644 test/test_passwd.c
|
|
|
|
diff --git a/test/Makemodule.am b/test/Makemodule.am
|
|
index 7b8dafe..488d17e 100644
|
|
--- a/test/Makemodule.am
|
|
+++ b/test/Makemodule.am
|
|
@@ -20,8 +20,17 @@ EXTRA_DIST += \
|
|
test/make-tree \
|
|
test/malformed-restore-double-owner.acl \
|
|
test/run \
|
|
+ test/runwrapper \
|
|
test/sort-getfacl-output \
|
|
+ test/test.passwd \
|
|
+ test/test.group \
|
|
$(TESTS)
|
|
|
|
+check_LTLIBRARIES = libtestlookup.la
|
|
+
|
|
+libtestlookup_la_SOURCES = test/test_passwd.c test/test_group.c
|
|
+libtestlookup_la_CFLAGS = -DBASEDIR=\"$(abs_srcdir)\"
|
|
+libtestlookup_la_LDFLAGS = -rpath $(abs_builddir)
|
|
+
|
|
AM_TESTS_ENVIRONMENT = PATH="$(abs_top_builddir):$$PATH";
|
|
-TEST_LOG_COMPILER = $(srcdir)/test/run
|
|
+TEST_LOG_COMPILER = $(srcdir)/test/runwrapper
|
|
diff --git a/test/run b/test/run
|
|
index fcbcf29..721b58a 100755
|
|
--- a/test/run
|
|
+++ b/test/run
|
|
@@ -43,12 +43,12 @@ use File::Basename qw(basename dirname);
|
|
use File::Path qw(rmtree);
|
|
use Getopt::Std;
|
|
use POSIX qw(isatty setuid getcwd);
|
|
-use vars qw($opt_l $opt_v);
|
|
+use vars qw($opt_l $opt_v $opt_t);
|
|
|
|
no warnings qw(taint);
|
|
|
|
$opt_l = ~0; # a really huge number
|
|
-getopts('l:v');
|
|
+getopts('l:vt:');
|
|
|
|
my ($OK, $FAILED) = ("ok", "failed");
|
|
if (isatty(fileno(STDOUT))) {
|
|
@@ -63,7 +63,18 @@ $ENV{"PATH"} = $ENV{"TESTDIR"} . ":$ENV{PATH}";
|
|
# Add the parent dir to PATH so we can find the compiled tools.
|
|
$ENV{"PATH"} = dirname(abs_path(dirname($0))) . ":$ENV{PATH}";
|
|
$ENV{"TUSER"} = getpwuid($>);
|
|
+if (!defined($ENV{"TUSER"})) {
|
|
+ # If the uid isn't found in the private passwd file, just use the
|
|
+ # uid directly.
|
|
+ $ENV{"TUSER"} = $>;
|
|
+}
|
|
$ENV{"TGROUP"} = getgrgid($));
|
|
+if (!defined($ENV{"TGROUP"})) {
|
|
+ # If the groupid isn't found in the private group file, just use the
|
|
+ # gid directly.
|
|
+ my @groups = split(/ /, $();
|
|
+ $ENV{"TGROUP"} = $groups[0];
|
|
+}
|
|
|
|
open(TEST_FILE, $ARGV[0]);
|
|
|
|
@@ -92,7 +103,7 @@ for (;;) {
|
|
if (defined $line) {
|
|
# Substitute %VAR and %{VAR} with environment variables.
|
|
$line =~ s[%(\w+)][$ENV{$1}]eg;
|
|
- $line =~ s[%{(\w+)}][$ENV{$1}]eg;
|
|
+ $line =~ s[%\{(\w+)\}][$ENV{$1}]eg;
|
|
}
|
|
if (defined $line) {
|
|
if ($line =~ s/^\s*< ?//) {
|
|
diff --git a/test/runwrapper b/test/runwrapper
|
|
new file mode 100755
|
|
index 0000000..38de337
|
|
--- /dev/null
|
|
+++ b/test/runwrapper
|
|
@@ -0,0 +1,6 @@
|
|
+#!/bin/bash
|
|
+if [ -e "$PWD/.libs/libtestlookup.so" ]; then
|
|
+ export LD_PRELOAD="$PWD/.libs/libtestlookup.so"
|
|
+fi
|
|
+
|
|
+$PWD/test/run $@
|
|
diff --git a/test/test.group b/test/test.group
|
|
new file mode 100644
|
|
index 0000000..5f9ca8f
|
|
--- /dev/null
|
|
+++ b/test/test.group
|
|
@@ -0,0 +1,3 @@
|
|
+bin:x:1:daemon
|
|
+daemon:x:2:
|
|
+users:x:100:
|
|
diff --git a/test/test.passwd b/test/test.passwd
|
|
new file mode 100644
|
|
index 0000000..a917bdd
|
|
--- /dev/null
|
|
+++ b/test/test.passwd
|
|
@@ -0,0 +1,5 @@
|
|
+root:x:0:0:root:/:/bin/false
|
|
+bin:x:1:1:bin:/:/bin/false
|
|
+daemon:x:2:2:Daemon:/:/bin/false
|
|
+domain\user:x:3:3:Test user:/:/bin/false
|
|
+domain\12345:x:4:4:Test user:/:/bin/false
|
|
diff --git a/test/test_group.c b/test/test_group.c
|
|
new file mode 100644
|
|
index 0000000..7fe6a19
|
|
--- /dev/null
|
|
+++ b/test/test_group.c
|
|
@@ -0,0 +1,154 @@
|
|
+#include <sys/types.h>
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+#include <stdlib.h>
|
|
+#include <errno.h>
|
|
+#include <libgen.h>
|
|
+#include <limits.h>
|
|
+#include <grp.h>
|
|
+
|
|
+#define TEST_GROUP "test/test.group"
|
|
+static char grfile[PATH_MAX];
|
|
+static void setup_grfile() __attribute__((constructor));
|
|
+
|
|
+void setup_grfile() {
|
|
+ snprintf(grfile, sizeof(grfile), "%s/%s", BASEDIR, TEST_GROUP);
|
|
+}
|
|
+
|
|
+#define ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
|
|
+#define ALIGN(x, a) ALIGN_MASK(x, (typeof(x))(a) - 1)
|
|
+
|
|
+int test_getgrent_r(FILE *file, struct group *grp, char *buf,
|
|
+ size_t buflen, struct group **result)
|
|
+{
|
|
+ char *line, *str, *remain;
|
|
+ int count, index = 0;
|
|
+ int gr_mem_cnt = 0;
|
|
+
|
|
+ *result = NULL;
|
|
+
|
|
+ line = fgets(buf, buflen, file);
|
|
+ if (!line)
|
|
+ return 0;
|
|
+
|
|
+ /* We'll stuff the gr_mem array in the remaining space in the buffer */
|
|
+ remain = buf + ALIGN(line + strlen(line) - buf, sizeof(char *));
|
|
+ grp->gr_mem = (char **)remain;
|
|
+ count = (buf + buflen - remain) / sizeof (char *);
|
|
+ if (!count) {
|
|
+ errno = ERANGE;
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ grp->gr_mem[--count] = NULL;
|
|
+
|
|
+ while ((str = strtok(line, ":"))) {
|
|
+ char *ptr;
|
|
+ switch (index++) {
|
|
+ case 0:
|
|
+ grp->gr_name = str;
|
|
+ break;
|
|
+ case 1:
|
|
+ grp->gr_passwd = str;
|
|
+ break;
|
|
+ case 2:
|
|
+ errno = 0;
|
|
+ grp->gr_gid = strtol(str, NULL, 10);
|
|
+ if (errno)
|
|
+ return -1;
|
|
+ break;
|
|
+ case 3:
|
|
+ while ((str = strtok_r(str, ",", &ptr))) {
|
|
+ if (count-- <= 0) {
|
|
+ errno = ERANGE;
|
|
+ return -1;
|
|
+ }
|
|
+ grp->gr_mem[gr_mem_cnt++] = str;
|
|
+ str = NULL;
|
|
+ }
|
|
+ }
|
|
+ line = NULL;
|
|
+ }
|
|
+
|
|
+ *result = grp;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int test_getgr_match(struct group *grp, char *buf, size_t buflen,
|
|
+ struct group **result,
|
|
+ int (*match)(const struct group *, const void *),
|
|
+ const void *data)
|
|
+{
|
|
+ FILE *file;
|
|
+ struct group *_result;
|
|
+
|
|
+ *result = NULL;
|
|
+
|
|
+ file = fopen(grfile, "r");
|
|
+ if (!file) {
|
|
+ errno = EBADF;
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ errno = 0;
|
|
+ while (!test_getgrent_r(file, grp, buf, buflen, &_result)) {
|
|
+ if (!_result)
|
|
+ break;
|
|
+ else if (match(grp, data)) {
|
|
+ *result = grp;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ fclose(file);
|
|
+ if (!errno && !*result)
|
|
+ errno = ENOENT;
|
|
+ if (errno)
|
|
+ return -1;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int match_name(const struct group *grp, const void *data)
|
|
+{
|
|
+ const char *name = data;
|
|
+ return !strcmp(grp->gr_name, name);
|
|
+}
|
|
+
|
|
+int getgrnam_r(const char *name, struct group *grp, char *buf, size_t buflen,
|
|
+ struct group **result)
|
|
+{
|
|
+ return test_getgr_match(grp, buf, buflen, result, match_name, name);
|
|
+}
|
|
+
|
|
+struct group *getgrnam(const char *name)
|
|
+{
|
|
+ static char buf[16384];
|
|
+ static struct group grp;
|
|
+ struct group *result;
|
|
+
|
|
+ (void) getgrnam_r(name, &grp, buf, sizeof(buf), &result);
|
|
+ return result;
|
|
+}
|
|
+
|
|
+static int match_gid(const struct group *grp, const void *data)
|
|
+{
|
|
+ gid_t gid = *(gid_t *)data;
|
|
+ return grp->gr_gid == gid;
|
|
+}
|
|
+
|
|
+int getgrgid_r(gid_t gid, struct group *grp, char *buf, size_t buflen,
|
|
+ struct group **result)
|
|
+{
|
|
+ return test_getgr_match(grp, buf, buflen, result, match_gid, &gid);
|
|
+}
|
|
+
|
|
+struct group *getgrgid(gid_t gid)
|
|
+{
|
|
+ static char buf[16384];
|
|
+ static struct group grp;
|
|
+ struct group *result;
|
|
+
|
|
+ (void) getgrgid_r(gid, &grp, buf, sizeof(buf), &result);
|
|
+ return result;
|
|
+}
|
|
diff --git a/test/test_passwd.c b/test/test_passwd.c
|
|
new file mode 100644
|
|
index 0000000..b5052f8
|
|
--- /dev/null
|
|
+++ b/test/test_passwd.c
|
|
@@ -0,0 +1,149 @@
|
|
+#include <sys/types.h>
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+#include <stdlib.h>
|
|
+#include <errno.h>
|
|
+#include <libgen.h>
|
|
+#include <limits.h>
|
|
+#include <pwd.h>
|
|
+
|
|
+#define TEST_PASSWD "test/test.passwd"
|
|
+static char pwfile[PATH_MAX];
|
|
+static void setup_pwfile() __attribute__((constructor));
|
|
+
|
|
+void setup_pwfile() {
|
|
+ snprintf(pwfile, sizeof(pwfile), "%s/%s", BASEDIR, TEST_PASSWD);
|
|
+}
|
|
+
|
|
+#define ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
|
|
+#define ALIGN(x, a) ALIGN_MASK(x, (typeof(x))(a) - 1)
|
|
+
|
|
+int test_getpwent_r(FILE *file, struct passwd *pwd, char *buf,
|
|
+ size_t buflen, struct passwd **result)
|
|
+{
|
|
+ char *str, *line;
|
|
+ int index = 0;
|
|
+
|
|
+ *result = NULL;
|
|
+
|
|
+ line = fgets(buf, buflen, file);
|
|
+ if (!line) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ while ((str = strtok(line, ":"))) {
|
|
+ switch (index++) {
|
|
+ case 0:
|
|
+ pwd->pw_name = str;
|
|
+ break;
|
|
+ case 1:
|
|
+ pwd->pw_passwd = str;
|
|
+ break;
|
|
+ case 2:
|
|
+ errno = 0;
|
|
+ pwd->pw_uid = strtol(str, NULL, 10);
|
|
+ if (errno)
|
|
+ return -1;
|
|
+ break;
|
|
+ case 3:
|
|
+ errno = 0;
|
|
+ pwd->pw_gid = strtol(str, NULL, 10);
|
|
+ if (errno)
|
|
+ return -1;
|
|
+ break;
|
|
+ case 4:
|
|
+ pwd->pw_gecos = str;
|
|
+ break;
|
|
+ case 5:
|
|
+ pwd->pw_dir = str;
|
|
+ break;
|
|
+ case 6:
|
|
+ pwd->pw_shell = str;
|
|
+ break;
|
|
+ }
|
|
+ line = NULL;
|
|
+ }
|
|
+
|
|
+ *result = pwd;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int test_getpw_match(struct passwd *pwd, char *buf, size_t buflen,
|
|
+ struct passwd **result,
|
|
+ int (*match)(const struct passwd *, const void *),
|
|
+ const void *data)
|
|
+{
|
|
+ FILE *file;
|
|
+ struct passwd *_result;
|
|
+
|
|
+ *result = NULL;
|
|
+
|
|
+ file = fopen(pwfile, "r");
|
|
+ if (!file) {
|
|
+ fprintf(stderr, "Failed to open %s\n", pwfile);
|
|
+ errno = EBADF;
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ errno = 0;
|
|
+ while (!test_getpwent_r(file, pwd, buf, buflen, &_result)) {
|
|
+ if (!_result)
|
|
+ break;
|
|
+ else if (match(pwd, data)) {
|
|
+ *result = pwd;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ fclose(file);
|
|
+ if (!errno && !*result)
|
|
+ errno = ENOENT;
|
|
+ if (errno)
|
|
+ return -1;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int match_name(const struct passwd *pwd, const void *data)
|
|
+{
|
|
+ const char *name = data;
|
|
+ return !strcmp(pwd->pw_name, name);
|
|
+}
|
|
+
|
|
+int getpwnam_r(const char *name, struct passwd *pwd, char *buf, size_t buflen,
|
|
+ struct passwd **result)
|
|
+{
|
|
+ return test_getpw_match(pwd, buf, buflen, result, match_name, name);
|
|
+}
|
|
+
|
|
+struct passwd *getpwnam(const char *name)
|
|
+{
|
|
+ static char buf[16384];
|
|
+ static struct passwd pwd;
|
|
+ struct passwd *result;
|
|
+
|
|
+ (void) getpwnam_r(name, &pwd, buf, sizeof(buf), &result);
|
|
+ return result;
|
|
+}
|
|
+
|
|
+static int match_uid(const struct passwd *pwd, const void *data)
|
|
+{
|
|
+ uid_t uid = *(uid_t *)data;
|
|
+ return pwd->pw_uid == uid;
|
|
+}
|
|
+
|
|
+int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf, size_t buflen,
|
|
+ struct passwd **result)
|
|
+{
|
|
+ return test_getpw_match(pwd, buf, buflen, result, match_uid, &uid);
|
|
+}
|
|
+
|
|
+struct passwd *getpwuid(uid_t uid)
|
|
+{
|
|
+ static char buf[16384];
|
|
+ static struct passwd pwd;
|
|
+ struct passwd *result;
|
|
+
|
|
+ (void) getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
|
|
+ return result;
|
|
+}
|
|
--
|
|
2.16.4
|
|
|