diff options
Diffstat (limited to 'src/nix-daemon/nix-daemon.cc')
-rw-r--r-- | src/nix-daemon/nix-daemon.cc | 112 |
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], [&]() { |