* Don't run setuid root when build-users is empty.

* Send startup errors to the client.
This commit is contained in:
Eelco Dolstra 2006-12-03 16:25:19 +00:00
parent 35247c4c9f
commit f4279bcde0
3 changed files with 54 additions and 29 deletions

View file

@ -244,7 +244,7 @@ static void setuidInit()
could also modify the Nix executables (say, replace them by a could also modify the Nix executables (say, replace them by a
Trojan horse), so the problem is already there. */ Trojan horse), so the problem is already there. */
#if 0 && HAVE_SETRESUID #if HAVE_SETRESUID
if (setresuid(nixUid, nixUid, nixUid)) abort(); if (setresuid(nixUid, nixUid, nixUid)) abort();
if (setresgid(nixGid, nixGid, nixGid)) abort(); if (setresgid(nixGid, nixGid, nixGid)) abort();
#elif HAVE_SETREUID #elif HAVE_SETREUID

View file

@ -73,6 +73,7 @@ RemoteStore::RemoteStore()
/* Send the magic greeting, check for the reply. */ /* Send the magic greeting, check for the reply. */
try { try {
processStderr();
writeInt(WORKER_MAGIC_1, to); writeInt(WORKER_MAGIC_1, to);
unsigned int magic = readInt(from); unsigned int magic = readInt(from);
if (magic != WORKER_MAGIC_2) throw Error("protocol mismatch"); if (magic != WORKER_MAGIC_2) throw Error("protocol mismatch");

View file

@ -4,6 +4,7 @@
#include "serialise.hh" #include "serialise.hh"
#include "worker-protocol.hh" #include "worker-protocol.hh"
#include "archive.hh" #include "archive.hh"
#include "globals.hh"
#include <iostream> #include <iostream>
#include <unistd.h> #include <unistd.h>
@ -30,7 +31,9 @@ static PathSet readStorePaths(Source & from)
} }
static Sink * _to; /* !!! should make writeToStderr an object */ static FdSource from(STDIN_FILENO);
static FdSink to(STDOUT_FILENO);
bool canSendStderr; bool canSendStderr;
@ -40,11 +43,13 @@ bool canSendStderr;
socket. */ socket. */
static void tunnelStderr(const unsigned char * buf, size_t count) static void tunnelStderr(const unsigned char * buf, size_t count)
{ {
if (canSendStderr)
writeFull(STDERR_FILENO, (unsigned char *) "L: ", 3);
writeFull(STDERR_FILENO, buf, count); writeFull(STDERR_FILENO, buf, count);
if (canSendStderr) { if (canSendStderr) {
try { try {
writeInt(STDERR_NEXT, *_to); writeInt(STDERR_NEXT, to);
writeString(string((char *) buf, count), *_to); writeString(string((char *) buf, count), to);
} catch (...) { } catch (...) {
/* Write failed; that means that the other side is /* Write failed; that means that the other side is
gone. */ gone. */
@ -118,7 +123,7 @@ static void stopWork()
throw SysError("ignoring SIGIO"); throw SysError("ignoring SIGIO");
canSendStderr = false; canSendStderr = false;
writeInt(STDERR_LAST, *_to); writeInt(STDERR_LAST, to);
} }
@ -225,21 +230,46 @@ static void performOp(Source & from, Sink & to, unsigned int op)
} }
static void processConnection(Source & from, Sink & to) static void processConnection()
{ {
store = boost::shared_ptr<StoreAPI>(new LocalStore(true));
unsigned int magic = readInt(from);
if (magic != WORKER_MAGIC_1) throw Error("protocol mismatch");
writeInt(WORKER_MAGIC_2, to);
debug("greeting exchanged");
_to = &to;
canSendStderr = false; canSendStderr = false;
writeToStderr = tunnelStderr; writeToStderr = tunnelStderr;
/* Allow us to receive SIGIO for events on the client socket. */
signal(SIGIO, SIG_IGN);
if (fcntl(STDIN_FILENO, F_SETOWN, getpid()) == -1)
throw SysError("F_SETOWN");
if (fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) | FASYNC) == -1)
throw SysError("F_SETFL");
/* Send startup error messages to the client. */
startWork();
try {
/* Prevent users from doing something very dangerous. */
if (setuidMode && geteuid() == 0 &&
querySetting("build-users", Strings()).size() == 0)
throw Error("if you run `nix-worker' setuid root, then you MUST set `build-users'!");
/* Open the store. */
store = boost::shared_ptr<StoreAPI>(new LocalStore(true));
stopWork();
} catch (Error & e) {
writeInt(STDERR_ERROR, to);
writeString(e.msg(), to);
return;
}
/* Exchange the greeting. */
unsigned int magic = readInt(from);
if (magic != WORKER_MAGIC_1) throw Error("protocol mismatch");
writeInt(WORKER_MAGIC_2, to);
debug("greeting exchanged");
/* Process client requests. */
bool quit = false; bool quit = false;
unsigned int opCount = 0; unsigned int opCount = 0;
@ -252,7 +282,7 @@ static void processConnection(Source & from, Sink & to)
try { try {
performOp(from, to, op); performOp(from, to, op);
} catch (Error & e) { } catch (Error & e) {
writeInt(STDERR_ERROR, *_to); writeInt(STDERR_ERROR, to);
writeString(e.msg(), to); writeString(e.msg(), to);
} }
@ -273,27 +303,21 @@ void run(Strings args)
if (arg == "--daemon") daemon = true; if (arg == "--daemon") daemon = true;
} }
/* Allow us to receive SIGIO for events on the client socket. */
signal(SIGIO, SIG_IGN);
if (fcntl(STDIN_FILENO, F_SETOWN, getpid()) == -1)
throw SysError("F_SETOWN");
if (fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) | FASYNC) == -1)
throw SysError("F_SETFL");
if (slave) { if (slave) {
FdSource source(STDIN_FILENO);
FdSink sink(STDOUT_FILENO);
/* This prevents us from receiving signals from the terminal /* This prevents us from receiving signals from the terminal
when we're running in setuid mode. */ when we're running in setuid mode. */
if (setsid() == -1) if (setsid() == -1)
throw SysError(format("creating a new session")); throw SysError(format("creating a new session"));
processConnection(source, sink); processConnection();
} }
else if (daemon) else if (daemon) {
if (setuidMode)
throw Error("daemon cannot be started in setuid mode");
throw Error("daemon mode not implemented"); throw Error("daemon mode not implemented");
}
else else
throw Error("must be run in either --slave or --daemon mode"); throw Error("must be run in either --slave or --daemon mode");