summaryrefslogtreecommitdiffstats
path: root/tests/common
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 02:22:06 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 02:22:06 +0000
commit741c1ef7a4f2ac316ad6e557ddbe03023413478d (patch)
tree38890f681daa26c57e865b4feca10d0ca53e1046 /tests/common
parentInitial commit. (diff)
downloadshadow-741c1ef7a4f2ac316ad6e557ddbe03023413478d.tar.xz
shadow-741c1ef7a4f2ac316ad6e557ddbe03023413478d.zip
Adding upstream version 1:4.5.upstream/1%4.5upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--tests/common/Makefile14
-rwxr-xr-xtests/common/compare_file.pl116
-rw-r--r--tests/common/config.sh121
-rw-r--r--tests/common/config_chroot-i386.list25
-rw-r--r--tests/common/config_chroot-powerpc.list25
-rw-r--r--tests/common/fopen_failure.c46
-rw-r--r--tests/common/link_failure.c51
-rw-r--r--tests/common/log.sh46
-rw-r--r--tests/common/open_RDONLY_failure.c51
-rw-r--r--tests/common/open_RDWR_failure.c51
-rw-r--r--tests/common/rename_failure.c50
-rw-r--r--tests/common/rmdir_failure.c51
-rw-r--r--tests/common/time_0.c16
-rw-r--r--tests/common/time_past.c52
-rw-r--r--tests/common/unlink_failure.c51
-rw-r--r--tests/common/unlinkat_failure.c62
16 files changed, 828 insertions, 0 deletions
diff --git a/tests/common/Makefile b/tests/common/Makefile
new file mode 100644
index 0000000..4ee04dd
--- /dev/null
+++ b/tests/common/Makefile
@@ -0,0 +1,14 @@
+all: \
+ fopen_failure.so \
+ link_failure.so \
+ open_RDONLY_failure.so \
+ open_RDWR_failure.so \
+ rename_failure.so \
+ rmdir_failure.so \
+ time_0.so \
+ time_past.so \
+ unlink_failure.so \
+ unlinkat_failure.so
+
+%.so: %.c
+ gcc -W -Wall -pedantic -g $< -shared -ldl -o $@
diff --git a/tests/common/compare_file.pl b/tests/common/compare_file.pl
new file mode 100755
index 0000000..eb498d3
--- /dev/null
+++ b/tests/common/compare_file.pl
@@ -0,0 +1,116 @@
+#!/usr/bin/perl
+
+open (TEMPLATE, $ARGV[0]) or die "Cannot open '".$ARGV[0]."': $!";
+my $template = join "", <TEMPLATE>;
+open (FILE, $ARGV[1]) or die "Cannot open '".$ARGV[1]."': $!";
+my $file = join "", <FILE>;
+
+my $today = int(time()/(24*3600));
+$template =~ s/\@TODAY\@/$today/g;
+
+my $tmp = $template;
+while ($tmp =~ m/^(.*?)([^\n]*):\@PASS_DES ([^:]*)\@:(.*)$/s) {
+ my $user = $2;
+ my $pass = $3;
+ $tmp = $4;
+ if ($file =~ m/^$user:/m) {
+ $file =~ s/^$user:([^:]*):(.*)$/$user:\@PASS_DES $pass\@:$2/m;
+ my $cryptpass = $1;
+ # Check the password
+ my $checkpass = qx|/usr/bin/openssl passwd -crypt -salt '$cryptpass' $pass 2>tmp/openssl.err|;
+ chomp $checkpass;
+
+ system "cat tmp/openssl.err"
+ if ($checkpass ne $cryptpass);
+ system "rm -f tmp/openssl.err";
+ die "Wrong password for $user: '$cryptpass'. Expected password: '$checkpass'\n"
+ if ($checkpass ne $cryptpass);
+ } else {
+ die "No user '$user' in ".$ARGV[1].".\n";
+ }
+}
+
+$tmp = $template;
+while ($tmp =~ m/^(.*?)([^\n]*):\@PASS_MD5 ([^:]*)\@:(.*)$/s) {
+ my $user = $2;
+ my $pass = $3;
+ $tmp = $4;
+ if ($file =~ m/^$user:/m) {
+ $file =~ s/^$user:([^:]*):(.*)$/$user:\@PASS_MD5 $pass\@:$2/m;
+ my $cryptpass = $1;
+ # Check the password
+ my $salt = $cryptpass;
+ $salt =~ s/^\$1\$//;
+ $salt =~ s/\$.*$//;
+ my $checkpass = qx|/usr/bin/openssl passwd -1 -salt '$salt' '$pass'|;
+ chomp $checkpass;
+
+ die "Wrong password for $user: '$cryptpass'. Expected password: '$checkpass'\n"
+ if ($checkpass ne $cryptpass);
+ } else {
+ die "No user '$user' in ".$ARGV[1].".\n";
+ }
+}
+
+$tmp = $template;
+while ($tmp =~ m/^(.*?)([^\n]*):\@PASS_SHA256 ([^:]*)\@:(.*)$/s) {
+ my $user = $2;
+ my $pass = $3;
+ $tmp = $4;
+ if ($file =~ m/^$user:/m) {
+ $file =~ s/^$user:([^:]*):(.*)$/$user:\@PASS_SHA256 $pass\@:$2/m;
+ my $cryptpass = $1;
+ # Check the password
+ my $salt = $cryptpass;
+ $salt =~ s/^\$5\$//;
+ my $rounds = "";
+ if ($salt =~ s/^rounds=([0-9]*)\$//) {
+ $rounds = "-R $1";
+ }
+
+ $salt =~ s/\$.*$//;
+ my $checkpass = qx!echo '$pass' | /usr/bin/mkpasswd -m sha-256 --salt '$salt' $rounds --stdin!;
+ chomp $checkpass;
+
+ die "Wrong password for $user: '$cryptpass'. Expected password: '$checkpass'\n"
+ if ($checkpass ne $cryptpass);
+ } else {
+ die "No user '$user' in ".$ARGV[1].".\n";
+ }
+}
+
+$tmp = $template;
+while ($tmp =~ m/^(.*?)([^\n]*):\@PASS_SHA512 ([^:]*)\@:(.*)$/s) {
+ my $user = $2;
+ my $pass = $3;
+ $tmp = $4;
+ if ($file =~ m/^$user:/m) {
+ $file =~ s/^$user:([^:]*):(.*)$/$user:\@PASS_SHA512 $pass\@:$2/m;
+ my $cryptpass = $1;
+ # Check the password
+ my $salt = $cryptpass;
+ $salt =~ s/^\$6\$//;
+ my $rounds = "";
+ if ($salt =~ s/^rounds=([0-9]*)\$//) {
+ $rounds = "-R $1";
+ }
+
+ $salt =~ s/\$.*$//;
+ my $checkpass = qx!echo '$pass' | /usr/bin/mkpasswd -m sha-512 --salt '$salt' $rounds --stdin!;
+ chomp $checkpass;
+
+ die "Wrong password for $user: '$cryptpass'. Expected password: '$checkpass'\n"
+ if ($checkpass ne $cryptpass);
+ } else {
+ die "No user '$user' in ".$ARGV[1].".\n";
+ }
+}
+
+
+exit 0 if ($file =~ m/^\Q$template\E$/s);
+
+print "Files differ.\n";
+
+system "diff", "-au", $ARGV[0], $ARGV[1];
+
+exit 1
diff --git a/tests/common/config.sh b/tests/common/config.sh
new file mode 100644
index 0000000..9b50485
--- /dev/null
+++ b/tests/common/config.sh
@@ -0,0 +1,121 @@
+# Generic functions to save, change, and restore configuration files
+
+set -e
+
+build_path=/root/build/shadow-4.1.5/
+
+# Save the configuration files in tmp.
+save_config ()
+{
+ [ ! -d tmp ] && mkdir tmp
+ find config -depth -path "*/.svn/*" -prune -o -type f -print | sed -e 's/config\///' |
+ while read file
+ do
+ mkdir -p "tmp/$(dirname "$file")"
+ [ -f "/$file" ] && cp -dp "/$file" "tmp/$file" || true
+ done
+}
+
+# Copy the config files from config to the system
+change_config ()
+{
+ find config -depth -path "*/.svn/*" -prune -o -type f -print | sed -e 's/config\///' |
+ while read file
+ do
+ cp -f "config/$file" "/$file"
+ done
+}
+
+# Restored the config files in the system.
+# The config files must be saved before with save_config ().
+restore_config ()
+{
+ find config -depth -path "*/.svn/*" -prune -o -type f -print | sed -e 's/config\///' |
+ while read file
+ do
+ if [ -f "tmp/$file" ]; then
+ cp -dp "tmp/$file" "/$file"
+ rm "tmp/$file"
+ else
+ rm -f "/$file"
+ fi
+ d="$(dirname "tmp/$file")"
+ while [ -n "$d" ] && [ "$d" != "." ]
+ do
+ rmdir "$d" 2>/dev/null || true
+ d="$(dirname "$d")"
+ done
+ done
+
+ rmdir tmp 2>/dev/null || true
+}
+
+prepare_chroot ()
+{
+ mkdir tmp/root
+ cp -rfdp config_chroot/* tmp/root/
+ find tmp/root/ -name .svn -type d -print0 | xargs -0 rm -rf
+
+ lists=/root/tests/common/config_chroot.list
+ [ -f config_chroot.list ] && lists="$lists config_chroot.list"
+ cat $lists | grep -v "#" | while read f
+ do
+ # Create parent directory if needed
+ d=$(dirname tmp/root/$f)
+ [ -d $d ] || mkdir -p $d
+ # Create hard link
+ ln $f tmp/root/$f
+ done
+
+ # Copy existing gcda
+ mkdir -p tmp/root$build_path/lib
+ mkdir -p tmp/root$build_path/libmisc
+ mkdir -p tmp/root$build_path/src
+ find "$build_path" -name "*.gcda" | while read f
+ do
+ ln $f tmp/root/$f
+ done
+}
+
+clean_chroot ()
+{
+ # Remove copied files
+ lists=/root/tests/common/config_chroot.list
+ [ -f config_chroot.list ] && lists="$lists config_chroot.list"
+ cat $lists | grep -v "#" | while read f
+ do
+ rm -f tmp/root/$f
+ # Remove parent directory if empty
+ d=$(dirname tmp/root/$f)
+ rmdir -p --ignore-fail-on-non-empty $d
+ done
+
+ find "$build_path" -name "*.gcda" | while read f
+ do
+ rm -f tmp/root/$f
+ done
+ find tmp/root -name "*.gcda" | while read f
+ do
+ g=${f#tmp/root}
+ mv "$f" "$g"
+ done
+ rmdir tmp/root$build_path/lib
+ rmdir tmp/root$build_path/libmisc
+ rmdir tmp/root$build_path/src
+ rmdir tmp/root$build_path
+ rmdir tmp/root/root/build
+ rmdir tmp/root/root
+
+ find config_chroot -type f | while read f
+ do
+ f=${f#config_chroot/}
+ rm -f tmp/root/$f
+ done
+
+ find config_chroot -depth -type d | while read d
+ do
+ d=${d#config_chroot}
+ [ -d "tmp/root$d" ] && rmdir tmp/root$d
+ done
+}
+
diff --git a/tests/common/config_chroot-i386.list b/tests/common/config_chroot-i386.list
new file mode 100644
index 0000000..ba7bf8a
--- /dev/null
+++ b/tests/common/config_chroot-i386.list
@@ -0,0 +1,25 @@
+/lib/i386-linux-gnu/ld-2.13.so
+/lib/i386-linux-gnu/ld-linux.so.2
+/lib/ld-linux.so.2
+/lib/i386-linux-gnu/libcrypt-2.13.so
+/lib/i386-linux-gnu/libcrypt.so.1
+/lib/i386-linux-gnu/libc-2.13.so
+/lib/i386-linux-gnu/libc.so.6
+/lib/i386-linux-gnu/libdl-2.13.so
+/lib/i386-linux-gnu/libdl.so.2
+/lib/i386-linux-gnu/libnsl-2.13.so
+/lib/i386-linux-gnu/libnsl.so.1
+/lib/i386-linux-gnu/libnss_compat-2.13.so
+/lib/i386-linux-gnu/libnss_compat.so.2
+/lib/i386-linux-gnu/libpamc.so.0
+/lib/i386-linux-gnu/libpamc.so.0.82.1
+/lib/i386-linux-gnu/libpam_misc.so.0
+/lib/i386-linux-gnu/libpam_misc.so.0.82.0
+/lib/i386-linux-gnu/libpam.so.0
+/lib/i386-linux-gnu/libpam.so.0.83.0
+/lib/i386-linux-gnu/libselinux.so.1
+/lib/i386-linux-gnu/security/pam_deny.so
+/lib/i386-linux-gnu/security/pam_permit.so
+/lib/i386-linux-gnu/security/pam_rootok.so
+/lib/i386-linux-gnu/security/pam_shells.so
+/lib/i386-linux-gnu/security/pam_unix.so
diff --git a/tests/common/config_chroot-powerpc.list b/tests/common/config_chroot-powerpc.list
new file mode 100644
index 0000000..e6c344e
--- /dev/null
+++ b/tests/common/config_chroot-powerpc.list
@@ -0,0 +1,25 @@
+/lib/powerpc-linux-gnu/ld-2.13.so
+/lib/powerpc-linux-gnu/ld.so.1
+/lib/ld.so.1
+/lib/powerpc-linux-gnu/libcrypt-2.13.so
+/lib/powerpc-linux-gnu/libcrypt.so.1
+/lib/powerpc-linux-gnu/libc-2.13.so
+/lib/powerpc-linux-gnu/libc.so.6
+/lib/powerpc-linux-gnu/libdl-2.13.so
+/lib/powerpc-linux-gnu/libdl.so.2
+/lib/powerpc-linux-gnu/libnsl-2.13.so
+/lib/powerpc-linux-gnu/libnsl.so.1
+/lib/powerpc-linux-gnu/libnss_compat-2.13.so
+/lib/powerpc-linux-gnu/libnss_compat.so.2
+/lib/powerpc-linux-gnu/libpamc.so.0
+/lib/powerpc-linux-gnu/libpamc.so.0.82.1
+/lib/powerpc-linux-gnu/libpam_misc.so.0
+/lib/powerpc-linux-gnu/libpam_misc.so.0.82.0
+/lib/powerpc-linux-gnu/libpam.so.0
+/lib/powerpc-linux-gnu/libpam.so.0.83.0
+/lib/powerpc-linux-gnu/libselinux.so.1
+/lib/powerpc-linux-gnu/security/pam_deny.so
+/lib/powerpc-linux-gnu/security/pam_permit.so
+/lib/powerpc-linux-gnu/security/pam_rootok.so
+/lib/powerpc-linux-gnu/security/pam_shells.so
+/lib/powerpc-linux-gnu/security/pam_unix.so
diff --git a/tests/common/fopen_failure.c b/tests/common/fopen_failure.c
new file mode 100644
index 0000000..750cd66
--- /dev/null
+++ b/tests/common/fopen_failure.c
@@ -0,0 +1,46 @@
+/*
+ * gcc fopen_failure.c -o fopen_failure.so -shared -ldl
+ * LD_PRELOAD=./fopen_failure.so FAILURE_PATH=/etc/shadow ./test /etc/shadow
+ */
+
+#define _GNU_SOURCE
+#include <dlfcn.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+typedef FILE * (*fopen_type) (const char *path, const char *mode);
+static fopen_type next_fopen;
+
+static const char *failure_path = NULL;
+
+FILE *fopen64 (const char *path, const char *mode)
+{
+printf ("fopen64(%s, %s)\n", path, mode);
+ if (NULL == next_fopen)
+ {
+ next_fopen = dlsym (RTLD_NEXT, "fopen64");
+ assert (NULL != next_fopen);
+ }
+ if (NULL == failure_path) {
+ failure_path = getenv ("FAILURE_PATH");
+ if (NULL == failure_path) {
+ fputs ("No FAILURE_PATH defined\n", stderr);
+ }
+ }
+
+ if ( (NULL != path)
+ && (NULL != failure_path)
+ && (strcmp (path, failure_path) == 0))
+ {
+ fprintf (stderr, "fopen64 FAILURE %s %s ...\n", path, mode);
+ errno = EIO;
+ return NULL;
+ }
+
+ return next_fopen (path, mode);
+}
+
diff --git a/tests/common/link_failure.c b/tests/common/link_failure.c
new file mode 100644
index 0000000..8cf460a
--- /dev/null
+++ b/tests/common/link_failure.c
@@ -0,0 +1,51 @@
+/*
+ * gcc link_failure.c -o link_failure.so -shared -ldl
+ * LD_PRELOAD=./link_failure.so FAILURE_PATH=/etc/shadow ./test /etc/shadow
+ */
+
+#define _GNU_SOURCE
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+typedef int (*link_type) (const char *oldpath, const char *newpath);
+static link_type next_link;
+
+static const char *failure_path = NULL;
+
+int link (const char *oldpath, const char *newpath)
+{
+ if (NULL == next_link)
+ {
+ next_link = dlsym (RTLD_NEXT, "link");
+ assert (NULL != next_link);
+ }
+ if (NULL == failure_path) {
+ failure_path = getenv ("FAILURE_PATH");
+ if (NULL == failure_path) {
+ fputs ("No FAILURE_PATH defined\n", stderr);
+ }
+ }
+
+ if ( (NULL != newpath)
+ && (NULL != failure_path)
+ && (strcmp (newpath, failure_path) == 0))
+ {
+ fprintf (stderr, "link FAILURE %s %s\n", oldpath, newpath);
+ errno = EIO;
+ return -1;
+ }
+
+ return next_link (oldpath, newpath);
+}
+
diff --git a/tests/common/log.sh b/tests/common/log.sh
new file mode 100644
index 0000000..4887970
--- /dev/null
+++ b/tests/common/log.sh
@@ -0,0 +1,46 @@
+# Helpers to log messages / status
+
+log_start ()
+{
+ test="$1"
+ rationale="$2"
+ cat << EOF
+
+###############################################################################
+#
+# Test: $test
+#
+###############################################################################
+#
+# Rationale: $rationale
+#
+###############################################################################
+EOF
+}
+
+log_end ()
+{
+ test="$1"
+ cat << EOF
+###############################################################################
+#
+# End of test $test
+#
+###############################################################################
+
+EOF
+}
+
+log_status ()
+{
+ test="$1"
+ status="$2"
+ cat << EOF
+###############################################################################
+#
+# Status of test $test: $status
+#
+###############################################################################
+EOF
+}
+
diff --git a/tests/common/open_RDONLY_failure.c b/tests/common/open_RDONLY_failure.c
new file mode 100644
index 0000000..e14859f
--- /dev/null
+++ b/tests/common/open_RDONLY_failure.c
@@ -0,0 +1,51 @@
+/*
+ * gcc open_RDONLY_failure.c -o open_RDONLY_failure.so -shared -ldl
+ * LD_PRELOAD=./open_RDONLY_failure.so FAILURE_PATH=/etc/shadow ./test /etc/shadow
+ */
+
+#define _GNU_SOURCE
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+typedef int (*open_type) (const char *pathname, int flag, ...);
+static open_type next_open64;
+
+static const char *failure_path = NULL;
+
+int open64 (const char *pathname, int flag, ...)
+{
+ if (NULL == next_open64)
+ {
+ next_open64 = dlsym (RTLD_NEXT, "open64");
+ assert (NULL != next_open64);
+ }
+ if (NULL == failure_path) {
+ failure_path = getenv ("FAILURE_PATH");
+ if (NULL == failure_path) {
+ fputs ("No FAILURE_PATH defined\n", stderr);
+ }
+ }
+
+ if ( (NULL != pathname)
+ && ((flag & O_ACCMODE) == O_RDONLY)
+ && (NULL != failure_path)
+ && (strcmp (pathname, failure_path) == 0))
+ {
+ fprintf (stderr, "open FAILURE %s %x ...\n", pathname, flag&O_ACCMODE);
+ errno = EIO;
+ return -1;
+ }
+
+ return next_open64 (pathname, flag);
+}
+
diff --git a/tests/common/open_RDWR_failure.c b/tests/common/open_RDWR_failure.c
new file mode 100644
index 0000000..5bf1069
--- /dev/null
+++ b/tests/common/open_RDWR_failure.c
@@ -0,0 +1,51 @@
+/*
+ * gcc open_RDWR_failure.c -o open_RDWR_failure.so -shared -ldl
+ * LD_PRELOAD=./open_RDWR_failure.so FAILURE_PATH=/etc/shadow ./test /etc/shadow
+ */
+
+#define _GNU_SOURCE
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+typedef int (*open_type) (const char *pathname, int flag, ...);
+static open_type next_open64;
+
+static const char *failure_path = NULL;
+
+int open64 (const char *pathname, int flag, ...)
+{
+ if (NULL == next_open64)
+ {
+ next_open64 = dlsym (RTLD_NEXT, "open64");
+ assert (NULL != next_open64);
+ }
+ if (NULL == failure_path) {
+ failure_path = getenv ("FAILURE_PATH");
+ if (NULL == failure_path) {
+ fputs ("No FAILURE_PATH defined\n", stderr);
+ }
+ }
+
+ if ( (NULL != pathname)
+ && ((flag & O_ACCMODE) == O_RDWR)
+ && (NULL != failure_path)
+ && (strcmp (pathname, failure_path) == 0))
+ {
+ fprintf (stderr, "open FAILURE %s %x ...\n", pathname, flag&O_ACCMODE);
+ errno = EIO;
+ return -1;
+ }
+
+ return next_open64 (pathname, flag);
+}
+
diff --git a/tests/common/rename_failure.c b/tests/common/rename_failure.c
new file mode 100644
index 0000000..dd02fe5
--- /dev/null
+++ b/tests/common/rename_failure.c
@@ -0,0 +1,50 @@
+/*
+ * gcc rename_failure.c -o rename_failure.so -shared -ldl
+ * LD_PRELOAD=./rename_failure.so FAILURE_PATH=/etc/shadow ./test /etc/shadow
+ */
+
+#define _GNU_SOURCE
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+typedef int (*rename_type) (const char *old, const char *new);
+static rename_type next_rename;
+
+static const char *failure_path = NULL;
+
+int rename (const char *old, const char *new)
+{
+ if (NULL == next_rename)
+ {
+ next_rename = dlsym (RTLD_NEXT, "rename");
+ assert (NULL != next_rename);
+ }
+ if (NULL == failure_path) {
+ failure_path = getenv ("FAILURE_PATH");
+ if (NULL == failure_path) {
+ fputs ("No FAILURE_PATH defined\n", stderr);
+ }
+ }
+
+ if ( (NULL != new)
+ && (NULL != failure_path)
+ && (strcmp (new, failure_path) == 0))
+ {
+ fprintf (stderr, "rename FAILURE %s %s\n", old, new);
+ errno = EIO;
+ return -1;
+ }
+
+ return next_rename (old, new);
+}
+
diff --git a/tests/common/rmdir_failure.c b/tests/common/rmdir_failure.c
new file mode 100644
index 0000000..9d775b1
--- /dev/null
+++ b/tests/common/rmdir_failure.c
@@ -0,0 +1,51 @@
+/*
+ * gcc rmdir_failure.c -o rmdir_failure.so -shared -ldl
+ * LD_PRELOAD=./rmdir_failure.so FAILURE_PATH=/etc/shadow ./test /etc/shadow
+ */
+
+#define _GNU_SOURCE
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+typedef int (*rmdir_type) (const char *path);
+static rmdir_type next_rmdir;
+
+static const char *failure_path = NULL;
+
+int rmdir (const char *path)
+{
+ if (NULL == next_rmdir)
+ {
+ next_rmdir = dlsym (RTLD_NEXT, "rmdir");
+ assert (NULL != next_rmdir);
+ }
+ if (NULL == failure_path) {
+ failure_path = getenv ("FAILURE_PATH");
+ if (NULL == failure_path) {
+ fputs ("No FAILURE_PATH defined\n", stderr);
+ }
+ }
+
+ if ( (NULL != path)
+ && (NULL != failure_path)
+ && (strcmp (path, failure_path) == 0))
+ {
+ fprintf (stderr, "rmdir FAILURE %s\n", path);
+ errno = EBUSY;
+ return -1;
+ }
+
+ return next_rmdir (path);
+}
+
diff --git a/tests/common/time_0.c b/tests/common/time_0.c
new file mode 100644
index 0000000..6937361
--- /dev/null
+++ b/tests/common/time_0.c
@@ -0,0 +1,16 @@
+/*
+ * gcc time_0.c -o time_0.so -shared
+ * LD_PRELOAD=./time_0.so ./test
+ */
+
+#include <stdio.h>
+#include <time.h>
+
+
+time_t time (time_t *t)
+{
+ fprintf (stderr, "time 0\n");
+
+ return (time_t)0;
+}
+
diff --git a/tests/common/time_past.c b/tests/common/time_past.c
new file mode 100644
index 0000000..d0eb741
--- /dev/null
+++ b/tests/common/time_past.c
@@ -0,0 +1,52 @@
+/*
+ * gcc time_past.c -o time_past.so -shared -ldl
+ * LD_PRELOAD=./time_past.so PAST_DAYS=2 ./test
+ */
+
+#define _GNU_SOURCE
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+typedef time_t (*time_type) (time_t *t);
+static time_type next_time;
+
+static int time_past = 0;
+static char *past = NULL;
+
+time_t time (time_t *t)
+{
+ time_t res;
+
+ if (NULL == next_time)
+ {
+ next_time = dlsym (RTLD_NEXT, "time");
+ assert (NULL != next_time);
+ }
+ if (NULL == past) {
+ const char *past = getenv ("PAST_DAYS");
+ if (NULL == past) {
+ fputs ("No PAST_DAYS defined\n", stderr);
+ }
+ time_past = atoi (past);
+ }
+
+ res = next_time (t);
+ res -= 24*60*60*time_past;
+
+ if (NULL != t) {
+ *t = res;
+ }
+
+ return res;
+}
+
diff --git a/tests/common/unlink_failure.c b/tests/common/unlink_failure.c
new file mode 100644
index 0000000..2281c8a
--- /dev/null
+++ b/tests/common/unlink_failure.c
@@ -0,0 +1,51 @@
+/*
+ * gcc unlink_failure.c -o unlink_failure.so -shared -ldl
+ * LD_PRELOAD=./unlink_failure.so FAILURE_PATH=/etc/shadow ./test /etc/shadow
+ */
+
+#define _GNU_SOURCE
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+typedef int (*unlink_type) (const char *path);
+static unlink_type next_unlink;
+
+static const char *failure_path = NULL;
+
+int unlink (const char *path)
+{
+ if (NULL == next_unlink)
+ {
+ next_unlink = dlsym (RTLD_NEXT, "unlink");
+ assert (NULL != next_unlink);
+ }
+ if (NULL == failure_path) {
+ failure_path = getenv ("FAILURE_PATH");
+ if (NULL == failure_path) {
+ fputs ("No FAILURE_PATH defined\n", stderr);
+ }
+ }
+
+ if ( (NULL != path)
+ && (NULL != failure_path)
+ && (strcmp (path, failure_path) == 0))
+ {
+ fprintf (stderr, "unlink FAILURE %s\n", path);
+ errno = EBUSY;
+ return -1;
+ }
+
+ return next_unlink (path);
+}
+
diff --git a/tests/common/unlinkat_failure.c b/tests/common/unlinkat_failure.c
new file mode 100644
index 0000000..5b8bf95
--- /dev/null
+++ b/tests/common/unlinkat_failure.c
@@ -0,0 +1,62 @@
+/*
+ * gcc unlinkat_failure.c -o unlinkat_failure.so -shared -ldl
+ * LD_PRELOAD=./unlinkat_failure.so FAILURE_PATH=/etc/shadow ./test /etc/shadow
+ */
+
+#define _GNU_SOURCE
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+typedef int (*unlinkat_type) (int dirfd, const char *pathname, int flags);
+static unlinkat_type next_unlinkat;
+
+static const char *failure_path = NULL;
+static dev_t failure_dev = -1;
+static ino_t failure_ino = -1;
+
+int unlinkat (int dirfd, const char *pathname, int flags)
+{
+ if (NULL == next_unlinkat)
+ {
+ next_unlinkat = dlsym (RTLD_NEXT, "unlinkat");
+ assert (NULL != next_unlinkat);
+ }
+ if (NULL == failure_path) {
+ struct stat sb;
+ failure_path = getenv ("FAILURE_PATH");
+ if (NULL == failure_path) {
+ fputs ("No FAILURE_PATH defined\n", stderr);
+ }
+ if (lstat (failure_path, &sb) != 0) {
+ fputs ("Can't lstat FAILURE_PATH\n", stderr);
+ }
+ failure_dev = sb.st_dev;
+ failure_ino = sb.st_ino;
+ }
+
+ if ( (NULL != pathname)
+ && (NULL != failure_path)) {
+ struct stat sb;
+ if ( (fstatat (dirfd, pathname, &sb, flags) == 0)
+ && (sb.st_dev == failure_dev)
+ && (sb.st_ino == failure_ino)) {
+ fprintf (stderr, "unlinkat FAILURE %s\n", failure_path);
+ errno = EBUSY;
+ return -1;
+ }
+ }
+
+ return next_unlinkat (dirfd, pathname, flags);
+}
+