From bdadb98de8fcd5ed99cca97071741e2775f3ada2 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 21 Feb 2007 17:34:02 +0000 Subject: [PATCH] * `nix-store --import' now also works in remote mode. The worker always requires a signature on the archive. This is to ensure that unprivileged users cannot add Trojan horses to the Nix store. --- src/libstore/remote-store.cc | 30 +++++++++++++++++++++------ src/libstore/remote-store.hh | 2 +- src/libstore/worker-protocol.hh | 3 ++- src/nix-worker/nix-worker.cc | 36 ++++++++++++++++++++++++++++++++- 4 files changed, 62 insertions(+), 9 deletions(-) diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc index dbeb7cf122..1aab90d38c 100644 --- a/src/libstore/remote-store.cc +++ b/src/libstore/remote-store.cc @@ -256,7 +256,13 @@ void RemoteStore::exportPath(const Path & path, bool sign, Path RemoteStore::importPath(bool requireSignature, Source & source) { - throw Error("not implemented"); + writeInt(wopImportPath, to); + /* We ignore requireSignature, since the worker forces it to true + anyway. */ + + processStderr(0, &source); + Path path = readStorePath(from); + return path; } @@ -340,16 +346,28 @@ void RemoteStore::collectGarbage(GCAction action, const PathSet & pathsToDelete, } -void RemoteStore::processStderr(Sink * sink) +void RemoteStore::processStderr(Sink * sink, Source * source) { unsigned int msg; - while ((msg = readInt(from)) == STDERR_NEXT || msg == STDERR_DATA) { - string s = readString(from); - if (msg == STDERR_DATA) { + while ((msg = readInt(from)) == STDERR_NEXT + || msg == STDERR_READ || msg == STDERR_WRITE) { + if (msg == STDERR_WRITE) { + string s = readString(from); if (!sink) throw Error("no sink"); (*sink)((const unsigned char *) s.c_str(), s.size()); } - else writeToStderr((const unsigned char *) s.c_str(), s.size()); + else if (msg == STDERR_READ) { + if (!source) throw Error("no source"); + unsigned int len = readInt(from); + unsigned char * buf = new unsigned char[len]; + AutoDeleteArray d(buf); + (*source)(buf, len); + writeString(string((const char *) buf, len), to); + } + else { + string s = readString(from); + writeToStderr((const unsigned char *) s.c_str(), s.size()); + } } if (msg == STDERR_ERROR) throw Error(readString(from)); diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh index f57dcbd938..19af8c0bed 100644 --- a/src/libstore/remote-store.hh +++ b/src/libstore/remote-store.hh @@ -70,7 +70,7 @@ private: FdSource from; Pid child; - void processStderr(Sink * sink = 0); + void processStderr(Sink * sink = 0, Source * source = 0); void forkSlave(); diff --git a/src/libstore/worker-protocol.hh b/src/libstore/worker-protocol.hh index e48fd5fe97..0126c8d59d 100644 --- a/src/libstore/worker-protocol.hh +++ b/src/libstore/worker-protocol.hh @@ -32,7 +32,8 @@ typedef enum { #define STDERR_NEXT 0x6f6c6d67 -#define STDERR_DATA 0x64617461 +#define STDERR_READ 0x64617461 // data needed from source +#define STDERR_WRITE 0x64617416 // data for sink #define STDERR_LAST 0x616c7473 #define STDERR_ERROR 0x63787470 diff --git a/src/nix-worker/nix-worker.cc b/src/nix-worker/nix-worker.cc index 04578a8b87..6e4c6e4a96 100644 --- a/src/nix-worker/nix-worker.cc +++ b/src/nix-worker/nix-worker.cc @@ -187,12 +187,37 @@ struct TunnelSink : Sink virtual void operator () (const unsigned char * data, unsigned int len) { - writeInt(STDERR_DATA, to); + writeInt(STDERR_WRITE, to); writeString(string((const char *) data, len), to); } }; +struct TunnelSource : Source +{ + Source & from; + TunnelSource(Source & from) : from(from) + { + } + virtual void operator () + (unsigned char * data, unsigned int len) + { + /* Careful: we're going to receive data from the client now, + so we have to disable the SIGPOLL handler. */ + setSigPollAction(false); + canSendStderr = false; + + writeInt(STDERR_READ, to); + writeInt(len, to); + string s = readString(from); + if (s.size() != len) throw Error("not enough data"); + memcpy(data, (const unsigned char *) s.c_str(), len); + + startWork(); + } +}; + + static void performOp(Source & from, Sink & to, unsigned int op) { switch (op) { @@ -289,6 +314,15 @@ static void performOp(Source & from, Sink & to, unsigned int op) break; } + case wopImportPath: { + startWork(); + TunnelSource source(from); + Path path = store->importPath(true, source); + stopWork(); + writeString(path, to); + break; + } + case wopBuildDerivations: { PathSet drvs = readStorePaths(from); startWork();