about summary refs log tree commit diff
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 2213a81ddd5d..9f9f9e0a9386 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 0d7045de18f7..5dab9847ad8f 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 84330016f310..fc44d02c6cba 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 29bd535f6ee0..6c3e5ee209ae 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 3f9b2a10d4ea..068c126596e7 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);