about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2004-08-20T15·22+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2004-08-20T15·22+0000
commite77fbe0fa2f7c2cfaee734dba049f0d8dd3dae15 (patch)
tree614c425a989b33c357387c04155e613db47b7f4a
parent2d35116c13e0c11210cb712f9ce6e8a38058f350 (diff)
* On systems that have the setresuid() and setresgid() system calls to
  set the real uid and gid to the effective uid and gid, the Nix
  binaries can be installed as owned by the Nix user and group instead
  of root, so no root involvement of any kind is necessary.

  Linux and FreeBSD have these functions.

-rw-r--r--configure.ac6
-rw-r--r--src/Makefile.am5
-rw-r--r--src/libmain/shared.cc29
3 files changed, 32 insertions, 8 deletions
diff --git a/configure.ac b/configure.ac
index 5dab9847ad8f..2ba8e92384a9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -151,6 +151,12 @@ if test "$setuid_hack" = "yes"; then
     AC_DEFINE(SETUID_HACK, 1, [whether to install Nix setuid])
 fi
 
+AC_CHECK_FUNC(setresuid, [HAVE_SETRESUID=1], [HAVE_SETRESUID=])
+AM_CONDITIONAL(HAVE_SETRESUID, test "$HAVE_SETRESUID" = "1")
+if test "$HAVE_SETRESUID" = "1"; then
+    AC_DEFINE(HAVE_SETRESUID, 1, [whether we have setresuid()])
+fi
+
 AC_ARG_WITH(nix-user, AC_HELP_STRING([--with-nix-user=USER],
   [user for Nix setuid binaries]),
   NIX_USER=$withval, NIX_USER=nix)
diff --git a/src/Makefile.am b/src/Makefile.am
index 6c3e5ee209ae..5637382172a2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -4,5 +4,10 @@ SUBDIRS = bin2c boost libutil libstore libmain nix-store nix-hash \
 SETUID_PROGS = nix-store nix-instantiate nix-env
 install-exec-hook:
 if SETUID_HACK
+if HAVE_SETRESUID
+	cd $(DESTDIR)$(bindir) && chown @NIX_USER@ $(SETUID_PROGS) \
+	  && chgrp @NIX_GROUP@ $(SETUID_PROGS) && chmod ug+s $(SETUID_PROGS)
+else
 	cd $(DESTDIR)$(bindir) && chown root $(SETUID_PROGS) && chmod u+s $(SETUID_PROGS)
 endif
+endif
diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc
index 068c126596e7..df56a77cf832 100644
--- a/src/libmain/shared.cc
+++ b/src/libmain/shared.cc
@@ -163,6 +163,16 @@ static void initAndRun(int argc, char * * argv)
 }
 
 
+#if HAVE_SETRESUID
+#define _setuid(uid) setresuid(uid, uid, uid)
+#define _setgid(gid) setresgid(gid, gid, gid)
+#else
+/* Only works properly when run by root. */
+#define _setuid(uid) setuid(uid)
+#define _setgid(gid) setgid(gid)
+#endif
+
+
 void switchToNixUser()
 {
 #if SETUID_HACK
@@ -186,6 +196,13 @@ void switchToNixUser()
         exit(1);
     }
 
+    /* !!! Apparently it is unspecified whether getgroups() includes
+       the effective gid.  In that case the following test is always
+       true *if* the program is installed setgid (which we do when we
+       have setresuid()).  On Linux this doesn't appear to be the
+       case, but we should switch to the real gid before doing this
+       test, and then switch back to the saved gid. */ 
+
     /* Check that the current user is a member of the Nix group. */
     bool found = false;
     for (int i = 0; i < nrGids; ++i)
@@ -196,15 +213,15 @@ void switchToNixUser()
 
     if (!found) {
         /* Not in the Nix group - drop all root/Nix privileges. */
-        setgid(getgid());
-        setuid(getuid());
+        _setgid(getgid());
+        _setuid(getuid());
         return;
     }
 
     /* Set the real, effective and saved gids to gr->gr_gid.  Also
        make very sure that this succeeded.  We switch the gid first
        because we cannot do it after we have dropped root uid. */
-    if (setgid(gr->gr_gid) != 0 ||
+    if (_setgid(gr->gr_gid) != 0 ||
         getgid() != gr->gr_gid ||
         getegid() != gr->gr_gid)
     {
@@ -222,7 +239,7 @@ void switchToNixUser()
     /* This will drop all root privileges, setting the real, effective
        and saved uids to pw->pw_uid.  Also make very sure that this
        succeeded.*/
-    if (setuid(pw->pw_uid) != 0 ||
+    if (_setuid(pw->pw_uid) != 0 ||
         getuid() != pw->pw_uid ||
         geteuid() != pw->pw_uid)
     {
@@ -240,11 +257,7 @@ int main(int argc, char * * argv)
 {
     /* If we are setuid root, we have to get rid of the excess
        privileges ASAP. */
-    printMsg(lvlError, format("%1% %2% %3% %4%\n") % getuid() % geteuid()
-        % getgid() % getegid());
     switchToNixUser();
-    printMsg(lvlError, format("%1% %2% %3% %4%\n") % getuid() % geteuid()
-        % getgid() % getegid());
     
     /* ATerm setup. */
     ATerm bottomOfStack;