From e77fbe0fa2f7c2cfaee734dba049f0d8dd3dae15 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 20 Aug 2004 15:22:33 +0000 Subject: [PATCH] * 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. --- configure.ac | 6 ++++++ src/Makefile.am | 5 +++++ src/libmain/shared.cc | 29 +++++++++++++++++++++-------- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index 5dab9847ad..2ba8e92384 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 6c3e5ee209..5637382172 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 068c126596..df56a77cf8 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;