File 0001-test-Add-helper-library-to-fake-passwd-group-files.patch of Package acl

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
openSUSE Build Service is sponsored by