summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorJeff Mahoney <jeffm@suse.com>2015-12-02 11:09:51 -0500
committerAndreas Gruenbacher <agruenba@redhat.com>2015-12-05 23:02:15 +0100
commitf2feb94748bd3c64ed153461afa51aebbd717821 (patch)
treede355dbfc9501b77b8f585f1f0d520c38d0c029b /test
parentfa03d2475682e4ab345c9a63bd6b88117bd45f0f (diff)
downloadacl-f2feb94748bd3c64ed153461afa51aebbd717821.tar.gz
test: Add helper library to fake passwd/group files
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.
Diffstat (limited to 'test')
-rw-r--r--test/Makemodule.am11
-rwxr-xr-xtest/run17
-rwxr-xr-xtest/runwrapper6
-rw-r--r--test/test.group3
-rw-r--r--test/test.passwd5
-rw-r--r--test/test_group.c154
-rw-r--r--test/test_passwd.c149
7 files changed, 341 insertions, 4 deletions
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;
+}