aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2006-11-30 19:54:43 +0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2006-11-30 19:54:43 +0000
commit765bdfe542d3250329dea98b69db2271419f31b6 (patch)
tree3eba766da3d72f36b5ea417b79e0dc275b954135
parent40b3f64b55f98e03b3173541b8d94cd924099223 (diff)
* When NIX_REMOTE is set to "slave", fork off nix-worker in slave
mode. Presumably nix-worker would be setuid to the Nix store user. The worker performs all operations on the Nix store and database, so the caller can be completely unprivileged. This is already much more secure than the old setuid scheme, since the worker doesn't need to do Nix expression evaluation and so on. Most importantly, this means that it doesn't need to access any user files, with all resulting security risks; it only performs pure store operations. Once this works, it is easy to move to a daemon model that forks off a worker for connections established through a Unix domain socket. That would be even more secure.
-rw-r--r--src/libstore/remote-store.cc54
-rw-r--r--src/libstore/remote-store.hh11
-rw-r--r--src/libstore/store-api.cc1
-rw-r--r--src/libutil/serialise.hh10
-rw-r--r--src/nix-worker/main.cc35
5 files changed, 87 insertions, 24 deletions
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index 27717a816..6f3c110a3 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -1,12 +1,64 @@
+#include "serialise.hh"
+#include "util.hh"
#include "remote-store.hh"
+#include <iostream>
+#include <unistd.h>
+
namespace nix {
RemoteStore::RemoteStore()
{
- throw Error("not implemented");
+ toChild.create();
+ fromChild.create();
+
+
+ /* Start the worker. */
+ string worker = "nix-worker";
+
+ child = fork();
+
+ switch (child) {
+
+ case -1:
+ throw SysError("unable to fork");
+
+ case 0:
+ try { /* child */
+
+ fromChild.readSide.close();
+ if (dup2(fromChild.writeSide, STDOUT_FILENO) == -1)
+ throw SysError("dupping write side");
+
+ toChild.writeSide.close();
+ if (dup2(toChild.readSide, STDIN_FILENO) == -1)
+ throw SysError("dupping read side");
+
+ execlp(worker.c_str(), worker.c_str(),
+ "-vvv", "--slave", NULL);
+
+ throw SysError(format("executing `%1%'") % worker);
+
+ } catch (std::exception & e) {
+ std::cerr << format("child error: %1%\n") % e.what();
+ }
+ quickExit(1);
+ }
+
+ fromChild.writeSide.close();
+ toChild.readSide.close();
+
+ from.fd = fromChild.readSide;
+ to.fd = toChild.writeSide;
+
+
+ /* Send the magic greeting, check for the reply. */
+ writeInt(0x6e697864, to);
+
+ unsigned int magic = readInt(from);
+ if (magic != 0x6478696e) throw Error("protocol mismatch");
}
diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh
index 8ebe5e397..da6911cf4 100644
--- a/src/libstore/remote-store.hh
+++ b/src/libstore/remote-store.hh
@@ -9,6 +9,12 @@
namespace nix {
+class Pipe;
+class Pid;
+struct FdSink;
+struct FdSource;
+
+
class RemoteStore : public StoreAPI
{
public:
@@ -44,6 +50,11 @@ public:
void ensurePath(const Path & storePath);
private:
+ Pipe toChild;
+ Pipe fromChild;
+ FdSink to;
+ FdSource from;
+ Pid child;
};
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 092d7f1e9..9e8bc36d7 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -91,6 +91,7 @@ Path makeFixedOutputPath(bool recursive,
#include "local-store.hh"
+#include "serialise.hh"
#include "remote-store.hh"
diff --git a/src/libutil/serialise.hh b/src/libutil/serialise.hh
index 459a693ee..6be10b552 100644
--- a/src/libutil/serialise.hh
+++ b/src/libutil/serialise.hh
@@ -33,6 +33,11 @@ struct FdSink : Sink
{
int fd;
+ FdSink()
+ {
+ fd = 0;
+ }
+
FdSink(int fd)
{
this->fd = fd;
@@ -47,6 +52,11 @@ struct FdSource : Source
{
int fd;
+ FdSource()
+ {
+ fd = 0;
+ }
+
FdSource(int fd)
{
this->fd = fd;
diff --git a/src/nix-worker/main.cc b/src/nix-worker/main.cc
index 4fe92a85a..f71b604d0 100644
--- a/src/nix-worker/main.cc
+++ b/src/nix-worker/main.cc
@@ -1,35 +1,21 @@
#include "shared.hh"
#include "local-store.hh"
#include "util.hh"
+#include "serialise.hh"
using namespace nix;
-/* !!! Mostly cut&pasted from util/archive.hh */
-/* Use buffered reads. */
-static unsigned int readInt(int fd)
+void processConnection(Source & from, Sink & to)
{
- unsigned char buf[8];
- readFull(fd, buf, sizeof(buf));
- if (buf[4] || buf[5] || buf[6] || buf[7])
- throw Error("implementation cannot deal with > 32-bit integers");
- return
- buf[0] |
- (buf[1] << 8) |
- (buf[2] << 16) |
- (buf[3] << 24);
-}
-
-
-void processConnection(int fdFrom, int fdTo)
-{
- store = openStore();
+ store = boost::shared_ptr<StoreAPI>(new LocalStore(true));
- unsigned int magic = readInt(fdFrom);
+ unsigned int magic = readInt(from);
if (magic != 0x6e697864) throw Error("protocol mismatch");
-
-
+ writeInt(0x6478696e, to);
+
+ debug("greeting exchanged");
}
@@ -43,8 +29,11 @@ void run(Strings args)
if (arg == "--slave") slave = true;
}
- if (slave)
- processConnection(STDIN_FILENO, STDOUT_FILENO);
+ if (slave) {
+ FdSource source(STDIN_FILENO);
+ FdSink sink(STDOUT_FILENO);
+ processConnection(source, sink);
+ }
else if (daemon)
throw Error("daemon mode not implemented");