about summary refs log tree commit diff
path: root/src/nix-daemon/nix-daemon.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/nix-daemon/nix-daemon.cc')
-rw-r--r--src/nix-daemon/nix-daemon.cc112
1 files changed, 73 insertions, 39 deletions
diff --git a/src/nix-daemon/nix-daemon.cc b/src/nix-daemon/nix-daemon.cc
index 8ec54e4580dc..bed7de0859a3 100644
--- a/src/nix-daemon/nix-daemon.cc
+++ b/src/nix-daemon/nix-daemon.cc
@@ -22,6 +22,10 @@
 #include <pwd.h>
 #include <grp.h>
 
+#if __APPLE__ || __FreeBSD__
+#include <sys/ucred.h>
+#endif
+
 using namespace nix;
 
 
@@ -509,11 +513,11 @@ static void performOp(bool trusted, unsigned int clientVersion,
     }
 
     case wopOptimiseStore:
-	startWork();
-	store->optimiseStore();
-	stopWork();
-	writeInt(1, to);
-	break;
+        startWork();
+        store->optimiseStore();
+        stopWork();
+        writeInt(1, to);
+        break;
 
     default:
         throw Error(format("invalid operation %1%") % op);
@@ -565,7 +569,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;
     }
@@ -606,6 +610,8 @@ static void processConnection(bool trusted)
         assert(!canSendStderr);
     };
 
+    canSendStderr = false;
+    _isInterrupted = false;
     printMsg(lvlDebug, format("%1% operations") % opCount);
 }
 
@@ -649,12 +655,51 @@ bool matchUser(const string & user, const string & group, const Strings & users)
 }
 
 
+struct PeerInfo
+{
+    bool pidKnown;
+    pid_t pid;
+    bool uidKnown;
+    uid_t uid;
+    bool gidKnown;
+    gid_t gid;
+};
+
+
+/* Get the identity of the caller, if possible. */
+static PeerInfo getPeerInfo(int remote)
+{
+    PeerInfo peer = { false, 0, false, 0, false, 0 };
+
+#if defined(SO_PEERCRED)
+
+    ucred cred;
+    socklen_t credLen = sizeof(cred);
+    if (getsockopt(remote, SOL_SOCKET, SO_PEERCRED, &cred, &credLen) == -1)
+        throw SysError("getting peer credentials");
+    peer = { true, cred.pid, true, cred.uid, true, cred.gid };
+
+#elif defined(LOCAL_PEERCRED)
+
+    xucred cred;
+    socklen_t credLen = sizeof(cred);
+    if (getsockopt(remote, SOL_LOCAL, LOCAL_PEERCRED, &cred, &credLen) == -1)
+        throw SysError("getting peer credentials");
+    peer = { false, 0, true, cred.cr_uid, false, 0 };
+
+#endif
+
+    return peer;
+}
+
+
 #define SD_LISTEN_FDS_START 3
 
 
 static void daemonLoop(char * * argv)
 {
-    chdir("/");
+    if (chdir("/") == -1)
+        throw SysError("cannot change current directory");
 
     /* Get rid of children automatically; don't let them become
        zombies. */
@@ -684,7 +729,8 @@ static void daemonLoop(char * * argv)
         /* Urgh, sockaddr_un allows path names of only 108 characters.
            So chdir to the socket directory so that we can pass a
            relative path name. */
-        chdir(dirOf(socketPath).c_str());
+        if (chdir(dirOf(socketPath).c_str()) == -1)
+            throw SysError("cannot change current directory");
         Path socketPathRel = "./" + baseNameOf(socketPath);
 
         struct sockaddr_un addr;
@@ -704,7 +750,8 @@ static void daemonLoop(char * * argv)
         if (res == -1)
             throw SysError(format("cannot bind to socket ‘%1%’") % socketPath);
 
-        chdir("/"); /* back to the root */
+        if (chdir("/") == -1) /* back to the root */
+            throw SysError("cannot change current directory");
 
         if (listen(fdSocket, 5) == -1)
             throw SysError(format("cannot listen on socket ‘%1%’") % socketPath);
@@ -735,22 +782,13 @@ static void daemonLoop(char * * argv)
             closeOnExec(remote);
 
             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)
-                throw SysError("getting peer credentials");
+            PeerInfo peer = getPeerInfo(remote);
 
-            clientPid = cred.pid;
+            struct passwd * pw = peer.uidKnown ? getpwuid(peer.uid) : 0;
+            string user = pw ? pw->pw_name : int2String(peer.uid);
 
-            struct passwd * pw = getpwuid(cred.uid);
-            string user = pw ? pw->pw_name : int2String(cred.uid);
-
-            struct group * gr = getgrgid(cred.gid);
-            string group = gr ? gr->gr_name : int2String(cred.gid);
+            struct group * gr = peer.gidKnown ? getgrgid(peer.gid) : 0;
+            string group = gr ? gr->gr_name : int2String(peer.gid);
 
             Strings trustedUsers = settings.get("trusted-users", Strings({"root"}));
             Strings allowedUsers = settings.get("allowed-users", Strings({"*"}));
@@ -761,11 +799,16 @@ static void daemonLoop(char * * argv)
             if (!trusted && !matchUser(user, group, allowedUsers))
                 throw Error(format("user ‘%1%’ is not allowed to connect to the Nix daemon") % user);
 
-            printMsg(lvlInfo, format((string) "accepted connection from pid %1%, user %2%"
-                    + (trusted ? " (trusted)" : "")) % clientPid % user);
-#endif
+            printMsg(lvlInfo, format((string) "accepted connection from pid %1%, user %2%" + (trusted ? " (trusted)" : ""))
+                % (peer.pidKnown ? int2String(peer.pid) : "<unknown>")
+                % (peer.uidKnown ? user : "<unknown>"));
 
             /* Fork a child to handle the connection. */
+            ProcessOptions options;
+            options.errorPrefix = "unexpected Nix daemon error: ";
+            options.dieWithParent = false;
+            options.runExitHandlers = true;
+            options.allowVfork = false;
             startProcess([&]() {
                 fdSocket.close();
 
@@ -777,8 +820,8 @@ static void daemonLoop(char * * argv)
                 setSigChldAction(false);
 
                 /* For debugging, stuff the pid into argv[1]. */
-                if (clientPid != -1 && argv[1]) {
-                    string processName = int2String(clientPid);
+                if (peer.pidKnown && argv[1]) {
+                    string processName = int2String(peer.pid);
                     strncpy(argv[1], processName.c_str(), strlen(argv[1]));
                 }
 
@@ -787,8 +830,8 @@ static void daemonLoop(char * * argv)
                 to.fd = remote;
                 processConnection(trusted);
 
-                _exit(0);
-            }, false, "unexpected Nix daemon error: ");
+                exit(0);
+            }, options);
 
         } catch (Interrupted & e) {
             throw;
@@ -799,15 +842,6 @@ static void daemonLoop(char * * argv)
 }
 
 
-void run(Strings args)
-{
-    for (Strings::iterator i = args.begin(); i != args.end(); ) {
-        string arg = *i++;
-    }
-
-}
-
-
 int main(int argc, char * * argv)
 {
     return handleExceptions(argv[0], [&]() {