about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2007-02-21T15·45+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2007-02-21T15·45+0000
commit43c4d18c6a4e1a8b129114439718e26c12b49ca8 (patch)
tree9e8927fbb240928c5d2f2a9fcee0f366d5630058 /src
parent46e0919ced4646004cc0701b188d0a68e24e8924 (diff)
* `nix-store --import': import an archive created by `nix-store
  --export' into the Nix store, and optionally check the cryptographic
  signatures against /nix/etc/nix/signing-key.pub.  (TODO: verify
  against a set of public keys.)

Diffstat (limited to 'src')
-rw-r--r--src/libstore/local-store.cc114
-rw-r--r--src/libstore/local-store.hh2
-rw-r--r--src/libstore/remote-store.cc6
-rw-r--r--src/libstore/remote-store.hh2
-rw-r--r--src/libstore/store-api.hh4
-rw-r--r--src/libutil/util.cc10
-rw-r--r--src/libutil/util.hh2
-rw-r--r--src/nix-store/nix-store.cc12
8 files changed, 142 insertions, 10 deletions
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index 991f28e8da..a7c9d58117 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -6,6 +6,7 @@
 #include "pathlocks.hh"
 #include "aterm.hh"
 #include "derivations-ast.hh"
+#include "worker-protocol.hh"
 #include "config.h"
     
 #include <iostream>
@@ -743,8 +744,6 @@ void LocalStore::exportPath(const Path & path, bool sign,
 
         writeInt(1, hashAndWriteSink);
         
-        //printMsg(lvlError, format("HASH = %1%") % printHash(hash));
-
         Path tmpDir = createTempDir();
         AutoDelete delTmp(tmpDir);
         Path hashFile = tmpDir + "/hash";
@@ -759,8 +758,6 @@ void LocalStore::exportPath(const Path & path, bool sign,
         args.push_back(hashFile);
         string signature = runProgram("openssl", true, args);
 
-        //printMsg(lvlError, format("SIGNATURE = %1%") % signature);
-
         writeString(signature, hashAndWriteSink);
         
     } else
@@ -768,6 +765,115 @@ void LocalStore::exportPath(const Path & path, bool sign,
 }
 
 
+struct HashAndReadSource : Source
+{
+    Source & readSource;
+    HashSink hashSink;
+    bool hashing;
+    HashAndReadSource(Source & readSource) : readSource(readSource), hashSink(htSHA256)
+    {
+        hashing = true;
+    }
+    virtual void operator ()
+        (unsigned char * data, unsigned int len)
+    {
+        readSource(data, len);
+        if (hashing) hashSink(data, len);
+    }
+};
+
+
+Path LocalStore::importPath(bool requireSignature, Source & source)
+{
+    HashAndReadSource hashAndReadSource(source);
+    
+    /* We don't yet know what store path this archive contains (the
+       store path follows the archive data proper), and besides, we
+       don't know yet whether the signature is valid. */
+    Path tmpDir = createTempDir(nixStore);
+    AutoDelete delTmp(tmpDir);
+    Path unpacked = tmpDir + "/unpacked";
+
+    restorePath(unpacked, hashAndReadSource);
+
+    unsigned int magic = readInt(hashAndReadSource);
+    if (magic != EXPORT_MAGIC)
+        throw Error("Nix archive cannot be imported; wrong format");
+
+    Path dstPath = readStorePath(hashAndReadSource);
+
+    PathSet references = readStorePaths(hashAndReadSource);
+
+    Path deriver = readStorePath(hashAndReadSource);
+
+    Hash hash = hashAndReadSource.hashSink.finish();
+    hashAndReadSource.hashing = false;
+
+    bool haveSignature = readInt(hashAndReadSource) == 1;
+
+    if (requireSignature && !haveSignature)
+        throw Error("imported archive lacks a signature");
+    
+    if (haveSignature) {
+        string signature = readString(hashAndReadSource);
+
+        Path sigFile = tmpDir + "/sig";
+        writeStringToFile(sigFile, signature);
+
+        Strings args;
+        args.push_back("rsautl");
+        args.push_back("-verify");
+        args.push_back("-inkey");
+        args.push_back(nixConfDir + "/signing-key.pub");
+        args.push_back("-pubin");
+        args.push_back("-in");
+        args.push_back(sigFile);
+        string hash2 = runProgram("openssl", true, args);
+
+        /* Note: runProgram() throws an exception if the signature is
+           invalid. */
+
+        if (printHash(hash) != hash2)
+            throw Error(
+                "signed hash doesn't match actual contents of imported "
+                "archive; archive could be corrupt, or someone is trying "
+                "to import a Trojan horse");
+    }
+
+    /* Do the actual import. */
+
+    /* !!! way too much code duplication with addTextToStore() etc. */
+    addTempRoot(dstPath);
+
+    if (!isValidPath(dstPath)) {
+
+        PathLocks outputLock(singleton<PathSet, Path>(dstPath));
+
+        if (!isValidPath(dstPath)) {
+
+            if (pathExists(dstPath)) deletePathWrapped(dstPath);
+
+            if (rename(unpacked.c_str(), dstPath.c_str()) == -1)
+                throw SysError(format("cannot move `%1%' to `%2%'")
+                    % unpacked % dstPath);
+
+            canonicalisePathMetaData(dstPath);
+            
+            Transaction txn(nixDB);
+            /* !!! if we were clever, we could prevent the hashPath()
+               here. */
+            registerValidPath(txn, dstPath,
+                hashPath(htSHA256, dstPath), references, "");
+            txn.commit();
+        }
+        
+        outputLock.setDeletion(true);
+    }
+    
+    return dstPath;
+}
+
+
 void deleteFromStore(const Path & _path, unsigned long long & bytesFreed)
 {
     bytesFreed = 0;
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index cae9d5c536..76d14c3a69 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -59,6 +59,8 @@ public:
     void exportPath(const Path & path, bool sign,
         Sink & sink);
 
+    Path importPath(bool requireSignature, Source & source);
+    
     void buildDerivations(const PathSet & drvPaths);
 
     void ensurePath(const Path & path);
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index 2fb4dd9802..801df58ad9 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -250,6 +250,12 @@ void RemoteStore::exportPath(const Path & path, bool sign,
 }
 
 
+Path RemoteStore::importPath(bool requireSignature, Source & source)
+{
+    throw Error("not implemented");
+}
+
+
 void RemoteStore::buildDerivations(const PathSet & drvPaths)
 {
     writeInt(wopBuildDerivations, to);
diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh
index 69fae2cd16..4c594b6066 100644
--- a/src/libstore/remote-store.hh
+++ b/src/libstore/remote-store.hh
@@ -47,6 +47,8 @@ public:
     void exportPath(const Path & path, bool sign,
         Sink & sink);
 
+    Path importPath(bool requireSignature, Source & source);
+    
     void buildDerivations(const PathSet & drvPaths);
 
     void ensurePath(const Path & path);
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index 6a1de616ca..1f2d60f11c 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -99,6 +99,10 @@ public:
     virtual void exportPath(const Path & path, bool sign,
         Sink & sink) = 0;
 
+    /* Import a NAR dump created by exportPath() into the Nix
+       store. */
+    virtual Path importPath(bool requireSignature, Source & source) = 0;
+
     /* Ensure that the output paths of the derivation are valid.  If
        they are already valid, this is a no-op.  Otherwise, validity
        can be reached in two ways.  First, if the output paths have
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 7671c7c7e4..1576e1e8b0 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -317,19 +317,19 @@ void makePathReadOnly(const Path & path)
 }
 
 
-static Path tempName()
+static Path tempName(const Path & tmpRoot)
 {
     static int counter = 0;
-    Path tmpRoot = canonPath(getEnv("TMPDIR", "/tmp"), true);
-    return (format("%1%/nix-%2%-%3%") % tmpRoot % getpid() % counter++).str();
+    Path tmpRoot2 = canonPath(tmpRoot.empty() ? getEnv("TMPDIR", "/tmp") : tmpRoot, true);
+    return (format("%1%/nix-%2%-%3%") % tmpRoot2 % getpid() % counter++).str();
 }
 
 
-Path createTempDir()
+Path createTempDir(const Path & tmpRoot)
 {
     while (1) {
         checkInterrupt();
-	Path tmpDir = tempName();
+	Path tmpDir = tempName(tmpRoot);
 	if (mkdir(tmpDir.c_str(), 0777) == 0) {
 	    /* Explicitly set the group of the directory.  This is to
 	       work around around problems caused by BSD's group
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 0ebf6f5a5f..3c4629957a 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -70,7 +70,7 @@ void deletePath(const Path & path, unsigned long long & bytesFreed);
 void makePathReadOnly(const Path & path);
 
 /* Create a temporary directory. */
-Path createTempDir();
+Path createTempDir(const Path & tmpRoot = "");
 
 /* Create a directory and all its parents, if necessary. */
 void createDirs(const Path & path);
diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc
index 7b56de7e4d..61ae4cf4f9 100644
--- a/src/nix-store/nix-store.cc
+++ b/src/nix-store/nix-store.cc
@@ -651,6 +651,16 @@ static void opExport(Strings opFlags, Strings opArgs)
 }
 
 
+static void opImport(Strings opFlags, Strings opArgs)
+{
+    if (!opFlags.empty()) throw UsageError("unknown flag");
+    if (!opArgs.empty()) throw UsageError("no arguments expected");
+    
+    FdSource source(STDIN_FILENO);
+    cout << format("%1%\n") % store->importPath(false, source);
+}
+
+
 /* Initialise the Nix databases. */
 static void opInit(Strings opFlags, Strings opArgs)
 {
@@ -722,6 +732,8 @@ void run(Strings args)
             op = opRestore;
         else if (arg == "--export")
             op = opExport;
+        else if (arg == "--import")
+            op = opImport;
         else if (arg == "--init")
             op = opInit;
         else if (arg == "--verify")