2009-06-08 Bruno Haible <bruno@clisp.org>
+ Tests for module 'idpriv-drop'.
+ * modules/idpriv-drop-tests: New file.
+ * tests/test-idpriv-drop.sh: New file.
+ * tests/test-idpriv-drop.su.sh: New file.
+ * tests/test-idpriv-drop.c: New file.
+
New module 'idpriv-drop'.
* lib/idpriv.h: New file.
* lib-idpriv-drop.c: New file.
--- /dev/null
+Notice:
+The 'idpriv-drop-tests' module asks the user for the root password. It is
+therefore not suitable for all environments. To disable it, pass option
+'--avoid=idpriv-drop-tests' to gnulib-tool.
+
+Files:
+tests/test-idpriv-drop.sh
+tests/test-idpriv-drop.su.sh
+tests/test-idpriv-drop.c
+
+Depends-on:
+stdbool
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-idpriv-drop.sh
+TESTS_ENVIRONMENT += EXEEXT='@EXEEXT@' srcdir='$(srcdir)'
+check_PROGRAMS += test-idpriv-drop
--- /dev/null
+/* Test of dropping uid/gid privileges of the current process permanently.
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include "idpriv.h"
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define ASSERT(expr) \
+ do \
+ { \
+ if (!(expr)) \
+ { \
+ fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
+ fflush (stderr); \
+ abort (); \
+ } \
+ } \
+ while (0)
+
+static void
+show_uids ()
+{
+#if HAVE_GETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */
+ uid_t real;
+ uid_t effective;
+ uid_t saved;
+ ASSERT (getresuid (&real, &effective, &saved) >= 0);
+ printf ("uids: real=%d effective=%d saved=%d",
+ (int) real, (int) effective, (int) saved);
+#elif HAVE_GETEUID
+ printf ("uids: real=%d effective=%d",
+ (int) getuid (), (int) geteuid());
+#elif HAVE_GETUID
+ printf ("uids: real=%d",
+ (int) getuid ());
+#endif
+}
+
+static void
+show_gids ()
+{
+#if HAVE_GETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */
+ gid_t real;
+ gid_t effective;
+ gid_t saved;
+ ASSERT (getresgid (&real, &effective, &saved) >= 0);
+ printf ("gids: real=%d effective=%d saved=%d",
+ (int) real, (int) effective, (int) saved);
+#elif HAVE_GETEGID
+ printf ("gids: real=%d effective=%d",
+ (int) getgid (), (int) getegid());
+#elif HAVE_GETGID
+ printf ("gids: real=%d",
+ (int) getgid ());
+#endif
+}
+
+static void
+show (const char *prefix)
+{
+ printf ("%s ", prefix);
+ show_uids ();
+ printf (" ");
+ show_gids ();
+ printf ("\n");
+}
+
+int
+main (int argc, char *argv[])
+{
+ bool verbose = false;
+ int i;
+
+#if HAVE_GETUID
+ int uid = getuid ();
+#endif
+#if HAVE_GETGID
+ int gid = getgid ();
+#endif
+
+ /* Parse arguments.
+ -v enables verbose output.
+ */
+ for (i = 1; i < argc; i++)
+ {
+ const char *arg = argv[i];
+ if (strcmp (arg, "-v") == 0)
+ verbose = true;
+ }
+
+ if (verbose)
+ show ("before drop:");
+
+ ASSERT (idpriv_drop () == 0);
+
+ if (verbose)
+ show ("after drop: ");
+
+ /* Verify that the privileges have really been dropped. */
+#if HAVE_GETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */
+ {
+ uid_t real;
+ uid_t effective;
+ uid_t saved;
+ if (getresuid (&real, &effective, &saved) < 0
+ || real != uid
+ || effective != uid
+ || saved != uid)
+ abort ();
+ }
+#else
+# if HAVE_GETEUID
+ if (geteuid () != uid)
+ abort ();
+# endif
+# if HAVE_GETUID
+ if (getuid () != uid)
+ abort ();
+# endif
+#endif
+#if HAVE_GETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */
+ {
+ gid_t real;
+ gid_t effective;
+ gid_t saved;
+ if (getresgid (&real, &effective, &saved) < 0
+ || real != gid
+ || effective != gid
+ || saved != gid)
+ abort ();
+ }
+#else
+# if HAVE_GETEGID
+ if (getegid () != gid)
+ abort ();
+# endif
+# if HAVE_GETGID
+ if (getgid () != gid)
+ abort ();
+# endif
+#endif
+
+ return 0;
+}
--- /dev/null
+#!/bin/sh
+
+# A POSIX compliant 'id' program.
+if test -f /usr/xpg4/bin/id; then
+ ID=/usr/xpg4/bin/id
+else
+ ID=id
+fi
+
+# The user's original uid and gid.
+uid=`$ID -u`
+gid=`$ID -g`
+
+if test `$ID -u` = 0; then
+ # No need to ask for a password.
+ "${srcdir}/test-idpriv-drop.su.sh" "$uid" "$gid"
+else
+ echo "Need root privileges for the 'test-idpriv-drop' test. Deny if you don't trust." > /dev/tty
+ if (type sudo) > /dev/null 2>&1; then
+ # Use the 'sudo' program.
+ sudo "${srcdir}/test-idpriv-drop.su.sh" "$uid" "$gid"
+ else
+ # Use the 'su' program.
+ su root -c "${srcdir}/test-idpriv-drop.su.sh \"$uid\" \"$gid\""
+ fi
+ result=$?
+ case $result in
+ 0) exit 0;;
+ 77) exit 77;;
+ 13) exit 1;;
+ *) echo "Skipping test: root privileges not granted"; exit 77;;
+ esac
+fi
--- /dev/null
+#!/bin/sh
+# This script must be run as superuser.
+
+origuid=$1
+origgid=$2
+
+# A POSIX compliant 'id' program.
+if test -f /usr/xpg4/bin/id; then
+ ID=/usr/xpg4/bin/id
+else
+ ID=id
+fi
+
+if test `$ID -u` != 0; then
+ echo "Skipping test: not superuser"
+ exit 77
+fi
+
+./test-idpriv-drop${EXEEXT} || exit 13 # normal
+
+chown root:root test-idpriv-drop${EXEEXT} 2>/dev/null || \
+chown root:wheel test-idpriv-drop${EXEEXT} 2>/dev/null || \
+ { echo "Skipping test: root privilege not sufficient on this file system"
+ exit 77
+ }
+chmod 4755 test-idpriv-drop${EXEEXT}
+./test-idpriv-drop${EXEEXT} || exit 13 # setuid root
+chmod 2755 test-idpriv-drop${EXEEXT}
+./test-idpriv-drop${EXEEXT} || exit 13 # setgid root
+chmod 6755 test-idpriv-drop${EXEEXT}
+./test-idpriv-drop${EXEEXT} || exit 13 # setuid and setgid root
+
+if chown nobody test-idpriv-drop${EXEEXT} 2>/dev/null; then
+ chmod 4755 test-idpriv-droptemp${EXEEXT}
+ ./test-idpriv-droptemp${EXEEXT} || exit 13 # setuid nobody
+ chmod 2755 test-idpriv-droptemp${EXEEXT}
+ ./test-idpriv-droptemp${EXEEXT} || exit 13 # setgid root
+ chmod 6755 test-idpriv-droptemp${EXEEXT}
+ ./test-idpriv-droptemp${EXEEXT} || exit 13 # setuid nobody and setgid root
+fi
+
+if chown root:nobody test-idpriv-drop${EXEEXT} 2>/dev/null; then
+ chmod 4755 test-idpriv-drop${EXEEXT}
+ ./test-idpriv-drop${EXEEXT} || exit 13 # setuid root
+ chmod 2755 test-idpriv-drop${EXEEXT}
+ ./test-idpriv-drop${EXEEXT} || exit 13 # setgid nobody
+ chmod 6755 test-idpriv-drop${EXEEXT}
+ ./test-idpriv-drop${EXEEXT} || exit 13 # setuid root and setgid nobody
+fi
+
+chown "$origuid:$origgid" test-idpriv-drop${EXEEXT}
+chmod 755 test-idpriv-drop${EXEEXT}