about summary refs log tree commit diff
path: root/src/libstore/local-store.cc
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/libstore/local-store.cc
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/libstore/local-store.cc')
-rw-r--r--src/libstore/local-store.cc114
1 files changed, 110 insertions, 4 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;