summary refs log tree commit diff
path: root/nix/nix-daemon
diff options
context:
space:
mode:
Diffstat (limited to 'nix/nix-daemon')
-rw-r--r--nix/nix-daemon/guix-daemon.cc25
-rw-r--r--nix/nix-daemon/nix-daemon.cc134
2 files changed, 94 insertions, 65 deletions
diff --git a/nix/nix-daemon/guix-daemon.cc b/nix/nix-daemon/guix-daemon.cc
index f096ed5a97..315744394f 100644
--- a/nix/nix-daemon/guix-daemon.cc
+++ b/nix/nix-daemon/guix-daemon.cc
@@ -154,8 +154,18 @@ parse_opt (int key, char *arg, struct argp_state *state)
       settings.useChroot = false;
       break;
     case GUIX_OPT_CHROOT_DIR:
-      settings.dirsInChroot.insert (arg);
-      break;
+      {
+	std::string chroot_dirs;
+
+	chroot_dirs = settings.get ("build-extra-chroot-dirs",
+				    (std::string) "");
+	if (chroot_dirs == "")
+	  chroot_dirs = arg;
+	else
+	  chroot_dirs = chroot_dirs + " " + arg;
+	settings.set("build-extra-chroot-dirs", chroot_dirs);
+	break;
+      }
     case GUIX_OPT_DISABLE_LOG_COMPRESSION:
       settings.compressLog = false;
       break;
@@ -328,11 +338,12 @@ main (int argc, char *argv[])
 
       if (settings.useChroot)
 	{
-	  foreach (PathSet::iterator, i, settings.dirsInChroot)
-	    {
-	      printMsg (lvlDebug,
-			format ("directory `%1%' added to the chroot") % *i);
-	    }
+	  std::string chroot_dirs;
+
+	  chroot_dirs = settings.get ("build-extra-chroot-dirs",
+				      (std::string) "");
+	  printMsg (lvlDebug,
+		    format ("extra chroot directories: '%1%'") % chroot_dirs);
 	}
 
       printMsg (lvlDebug,
diff --git a/nix/nix-daemon/nix-daemon.cc b/nix/nix-daemon/nix-daemon.cc
index 8814fe3155..e42d602a3a 100644
--- a/nix/nix-daemon/nix-daemon.cc
+++ b/nix/nix-daemon/nix-daemon.cc
@@ -7,6 +7,8 @@
 #include "affinity.hh"
 #include "globals.hh"
 
+#include <algorithm>
+
 #include <cstring>
 #include <unistd.h>
 #include <signal.h>
@@ -17,6 +19,8 @@
 #include <sys/un.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <pwd.h>
+#include <grp.h>
 
 using namespace nix;
 
@@ -44,7 +48,6 @@ static FdSource from(STDIN_FILENO);
 static FdSink to(STDOUT_FILENO);
 
 bool canSendStderr;
-pid_t myPid;
 
 
 
@@ -54,11 +57,7 @@ pid_t myPid;
    socket. */
 static void tunnelStderr(const unsigned char * buf, size_t count)
 {
-    /* Don't send the message to the client if we're a child of the
-       process handling the connection.  Otherwise we could screw up
-       the protocol.  It's up to the parent to redirect stderr and
-       send it to the client somehow (e.g., as in build.cc). */
-    if (canSendStderr && myPid == getpid()) {
+    if (canSendStderr) {
         try {
             writeInt(STDERR_NEXT, to);
             writeString(buf, count, to);
@@ -284,15 +283,6 @@ static void performOp(bool trusted, unsigned int clientVersion,
 {
     switch (op) {
 
-#if 0
-    case wopQuit: {
-        /* Close the database. */
-        store.reset((StoreAPI *) 0);
-        writeInt(1, to);
-        break;
-    }
-#endif
-
     case wopIsValidPath: {
         /* 'readStorePath' could raise an error leading to the connection
            being closed.  To be able to recover from an invalid path error,
@@ -450,7 +440,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
     case wopImportPaths: {
         startWork();
         TunnelSource source(from);
-        Paths paths = store->importPaths(true, source);
+        Paths paths = store->importPaths(!trusted, source);
         stopWork();
         writeStrings(paths, to);
         break;
@@ -650,6 +640,13 @@ static void performOp(bool trusted, unsigned int clientVersion,
         break;
     }
 
+    case wopOptimiseStore:
+	startWork();
+	store->optimiseStore();
+	stopWork();
+	writeInt(1, to);
+	break;
+
     default:
         throw Error(format("invalid operation %1%") % op);
     }
@@ -659,7 +656,6 @@ static void performOp(bool trusted, unsigned int clientVersion,
 static void processConnection(bool trusted)
 {
     canSendStderr = false;
-    myPid = getpid();
     _writeToStderr = tunnelStderr;
 
 #ifdef HAVE_HUP_NOTIFICATION
@@ -708,7 +704,7 @@ static void processConnection(bool trusted)
         to.flush();
 
     } catch (Error & e) {
-        stopWork(false, e.msg());
+        stopWork(false, e.msg(), GET_PROTOCOL_MINOR(clientVersion) >= 8 ? 1 : 0);
         to.flush();
         return;
     }
@@ -735,12 +731,10 @@ static void processConnection(bool trusted)
                during addTextToStore() / importPath().  If that
                happens, just send the error message and exit. */
             bool errorAllowed = canSendStderr;
-            if (!errorAllowed) printMsg(lvlError, format("error processing client input: %1%") % e.msg());
             stopWork(false, e.msg(), GET_PROTOCOL_MINOR(clientVersion) >= 8 ? e.status : 0);
-            if (!errorAllowed) break;
+            if (!errorAllowed) throw;
         } catch (std::bad_alloc & e) {
-            if (canSendStderr)
-                stopWork(false, "Nix daemon out of memory", GET_PROTOCOL_MINOR(clientVersion) >= 8 ? 1 : 0);
+            stopWork(false, "Nix daemon out of memory", GET_PROTOCOL_MINOR(clientVersion) >= 8 ? 1 : 0);
             throw;
         }
 
@@ -749,7 +743,7 @@ static void processConnection(bool trusted)
         assert(!canSendStderr);
     };
 
-    printMsg(lvlError, format("%1% operations") % opCount);
+    printMsg(lvlDebug, format("%1% operations") % opCount);
 }
 
 
@@ -771,6 +765,27 @@ static void setSigChldAction(bool autoReap)
 }
 
 
+bool matchUser(const string & user, const string & group, const Strings & users)
+{
+    if (find(users.begin(), users.end(), "*") != users.end())
+        return true;
+
+    if (find(users.begin(), users.end(), user) != users.end())
+        return true;
+
+    for (auto & i : users)
+        if (string(i, 0, 1) == "@") {
+            if (group == string(i, 1)) return true;
+            struct group * gr = getgrnam(i.c_str() + 1);
+            if (!gr) continue;
+            for (char * * mem = gr->gr_mem; *mem; mem++)
+                if (user == string(*mem)) return true;
+        }
+
+    return false;
+}
+
+
 #define SD_LISTEN_FDS_START 3
 
 
@@ -856,58 +871,61 @@ static void daemonLoop()
 
             closeOnExec(remote);
 
-            /* Get the identity of the caller, if possible. */
-            uid_t clientUid = -1;
-            pid_t clientPid = -1;
             bool trusted = false;
+            pid_t clientPid = -1;
 
 #if defined(SO_PEERCRED)
+            /* Get the identity of the caller, if possible. */
             ucred cred;
             socklen_t credLen = sizeof(cred);
-            if (getsockopt(remote, SOL_SOCKET, SO_PEERCRED, &cred, &credLen) != -1) {
-                clientPid = cred.pid;
-                clientUid = cred.uid;
-                if (clientUid == 0) trusted = true;
-            }
-#endif
+            if (getsockopt(remote, SOL_SOCKET, SO_PEERCRED, &cred, &credLen) == -1)
+                throw SysError("getting peer credentials");
 
-            printMsg(lvlInfo, format("accepted connection from pid %1%, uid %2%") % clientPid % clientUid);
+            clientPid = cred.pid;
 
-            /* Fork a child to handle the connection. */
-            pid_t child;
-            child = fork();
+            struct passwd * pw = getpwuid(cred.uid);
+            string user = pw ? pw->pw_name : int2String(cred.uid);
 
-            switch (child) {
+            struct group * gr = getgrgid(cred.gid);
+            string group = gr ? gr->gr_name : int2String(cred.gid);
 
-            case -1:
-                throw SysError("unable to fork");
+            Strings trustedUsers = settings.get("trusted-users", Strings({"root"}));
+            Strings allowedUsers = settings.get("allowed-users", Strings({"*"}));
 
-            case 0:
-                try { /* child */
+            if (matchUser(user, group, trustedUsers))
+                trusted = true;
 
-                    /* Background the daemon. */
-                    if (setsid() == -1)
-                        throw SysError(format("creating a new session"));
+            if (!trusted && !matchUser(user, group, allowedUsers))
+                throw Error(format("user `%1%' is not allowed to connect to the Nix daemon") % user);
 
-                    /* Restore normal handling of SIGCHLD. */
-                    setSigChldAction(false);
+            printMsg(lvlInfo, format((string) "accepted connection from pid %1%, user %2%"
+                    + (trusted ? " (trusted)" : "")) % clientPid % user);
+#endif
+
+            /* Fork a child to handle the connection. */
+            startProcess([&]() {
+                fdSocket.close();
 
-                    /* For debugging, stuff the pid into argv[1]. */
-                    if (clientPid != -1 && argvSaved[1]) {
-                        string processName = int2String(clientPid);
-                        strncpy(argvSaved[1], processName.c_str(), strlen(argvSaved[1]));
-                    }
+                /* Background the daemon. */
+                if (setsid() == -1)
+                    throw SysError(format("creating a new session"));
 
-                    /* Handle the connection. */
-                    from.fd = remote;
-                    to.fd = remote;
-                    processConnection(trusted);
+                /* Restore normal handling of SIGCHLD. */
+                setSigChldAction(false);
 
-                } catch (std::exception & e) {
-                    writeToStderr("unexpected Nix daemon error: " + string(e.what()) + "\n");
+                /* For debugging, stuff the pid into argv[1]. */
+                if (clientPid != -1 && argvSaved[1]) {
+                    string processName = int2String(clientPid);
+                    strncpy(argvSaved[1], processName.c_str(), strlen(argvSaved[1]));
                 }
+
+                /* Handle the connection. */
+                from.fd = remote;
+                to.fd = remote;
+                processConnection(trusted);
+
                 exit(0);
-            }
+            }, false, "unexpected Nix daemon error: ", true);
 
         } catch (Interrupted & e) {
             throw;