aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am17
-rw-r--r--configure.ac22
-rw-r--r--scripts/nix-push.in2
-rw-r--r--src/Makefile.am6
-rw-r--r--src/libmain/shared.cc82
5 files changed, 121 insertions, 8 deletions
diff --git a/Makefile.am b/Makefile.am
index 2213a81dd..9f9f9e0a9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -14,16 +14,19 @@ relname:
install-data-local: init-state
if INIT_STATE
+if SETUID_HACK
+INIT_FLAGS = -g @NIX_GROUP@ -o @NIX_USER@
+endif
init-state:
- $(INSTALL) -d $(DESTDIR)$(localstatedir)/nix
- $(INSTALL) -d $(DESTDIR)$(localstatedir)/nix/db
- $(INSTALL) -d $(DESTDIR)$(localstatedir)/log/nix
- $(INSTALL) -d $(DESTDIR)$(localstatedir)/nix/profiles
- $(INSTALL) -d $(DESTDIR)$(localstatedir)/nix/gcroots
- $(INSTALL) -d $(DESTDIR)$(localstatedir)/nix/gcroots/tmp
+ $(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix
+ $(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/db
+ $(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/log/nix
+ $(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/profiles
+ $(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/gcroots
+ $(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/gcroots/tmp
rm -f $(DESTDIR)$(localstatedir)/nix/gcroots/profiles
ln -s $(localstatedir)/nix/profiles $(DESTDIR)$(localstatedir)/nix/gcroots/profiles
- $(INSTALL) -d $(DESTDIR)$(prefix)/store
+ $(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(prefix)/store
# $(bindir)/nix-store --init
else
init-state:
diff --git a/configure.ac b/configure.ac
index 0d7045de1..5dab9847a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -142,6 +142,28 @@ AC_ARG_ENABLE(init-state, AC_HELP_STRING([--disable-init-state],
init_state=$enableval, init_state=yes)
AM_CONDITIONAL(INIT_STATE, test "$init_state" = "yes")
+
+AC_ARG_ENABLE(setuid, AC_HELP_STRING([--enable-setuid],
+ [install Nix setuid]),
+ setuid_hack=$enableval, setuid_hack=no)
+AM_CONDITIONAL(SETUID_HACK, test "$setuid_hack" = "yes")
+if test "$setuid_hack" = "yes"; then
+ AC_DEFINE(SETUID_HACK, 1, [whether to install Nix setuid])
+fi
+
+AC_ARG_WITH(nix-user, AC_HELP_STRING([--with-nix-user=USER],
+ [user for Nix setuid binaries]),
+ NIX_USER=$withval, NIX_USER=nix)
+AC_SUBST(NIX_USER)
+AC_DEFINE_UNQUOTED(NIX_USER, ["$NIX_USER"], [Nix user])
+
+AC_ARG_WITH(nix-group, AC_HELP_STRING([--with-nix-group=USER],
+ [group for Nix setuid binaries]),
+ NIX_GROUP=$withval, NIX_GROUP=nix)
+AC_SUBST(NIX_GROUP)
+AC_DEFINE_UNQUOTED(NIX_GROUP, ["$NIX_GROUP"], [Nix group])
+
+
AM_CONFIG_HEADER([config.h])
AC_CONFIG_FILES([Makefile
externals/Makefile
diff --git a/scripts/nix-push.in b/scripts/nix-push.in
index 84330016f..fc44d02c6 100644
--- a/scripts/nix-push.in
+++ b/scripts/nix-push.in
@@ -92,7 +92,7 @@ while (scalar @tmp > 0) {
my @tmp2 = @tmp[0..$n - 1];
@tmp = @tmp[$n..scalar @tmp - 1];
- system "@bindir@/nix-store --realise -B @tmp2 > /dev/null";
+ system "@bindir@/nix-store --realise @tmp2 > /dev/null";
if ($?) { die "`nix-store --realise' failed"; }
open NARPATHS, "@bindir@/nix-store --query --list @tmp2 |" or die "cannot run nix";
diff --git a/src/Makefile.am b/src/Makefile.am
index 29bd535f6..6c3e5ee20 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,2 +1,8 @@
SUBDIRS = bin2c boost libutil libstore libmain nix-store nix-hash \
libexpr nix-instantiate nix-env log2xml
+
+SETUID_PROGS = nix-store nix-instantiate nix-env
+install-exec-hook:
+if SETUID_HACK
+ cd $(DESTDIR)$(bindir) && chown root $(SETUID_PROGS) && chmod u+s $(SETUID_PROGS)
+endif
diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc
index 3f9b2a10d..068c12659 100644
--- a/src/libmain/shared.cc
+++ b/src/libmain/shared.cc
@@ -5,6 +5,9 @@
#include <sys/stat.h>
#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+
extern "C" {
#include <aterm2.h>
}
@@ -160,10 +163,89 @@ static void initAndRun(int argc, char * * argv)
}
+void switchToNixUser()
+{
+#if SETUID_HACK
+
+ /* Here we set the uid and gid to the Nix user and group,
+ respectively, IF the current (real) user is a member of the Nix
+ group. Otherwise we just drop all privileges. */
+
+ /* Lookup the Nix gid. */
+ struct group * gr = getgrnam(NIX_GROUP);
+ if (!gr) {
+ cerr << format("missing group `%1%'\n") % NIX_GROUP;
+ exit(1);
+ }
+
+ /* Get the supplementary group IDs for the current user. */
+ int maxGids = 512, nrGids;
+ gid_t gids[maxGids];
+ if ((nrGids = getgroups(maxGids, gids)) == -1) {
+ cerr << format("unable to query gids\n");
+ exit(1);
+ }
+
+ /* Check that the current user is a member of the Nix group. */
+ bool found = false;
+ for (int i = 0; i < nrGids; ++i)
+ if (gids[i] == gr->gr_gid) {
+ found = true;
+ break;
+ }
+
+ if (!found) {
+ /* Not in the Nix group - drop all root/Nix privileges. */
+ 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 ||
+ getgid() != gr->gr_gid ||
+ getegid() != gr->gr_gid)
+ {
+ cerr << format("unable to set gid to `%1%'\n") % NIX_GROUP;
+ exit(1);
+ }
+
+ /* Lookup the Nix uid. */
+ struct passwd * pw = getpwnam(NIX_USER);
+ if (!pw) {
+ cerr << format("missing user `%1%'\n") % NIX_USER;
+ exit(1);
+ }
+
+ /* 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 ||
+ getuid() != pw->pw_uid ||
+ geteuid() != pw->pw_uid)
+ {
+ cerr << format("unable to set uid to `%1%'\n") % NIX_USER;
+ exit(1);
+ }
+
+#endif
+}
+
+
static char buf[1024];
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;
ATinit(argc, argv, &bottomOfStack);