* 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.)
This commit is contained in:
parent
46e0919ced
commit
43c4d18c6a
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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")
|
||||
|
|
Loading…
Reference in a new issue