forked from lix-project/lix
* 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 "pathlocks.hh"
|
||||||
#include "aterm.hh"
|
#include "aterm.hh"
|
||||||
#include "derivations-ast.hh"
|
#include "derivations-ast.hh"
|
||||||
|
#include "worker-protocol.hh"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -743,8 +744,6 @@ void LocalStore::exportPath(const Path & path, bool sign,
|
||||||
|
|
||||||
writeInt(1, hashAndWriteSink);
|
writeInt(1, hashAndWriteSink);
|
||||||
|
|
||||||
//printMsg(lvlError, format("HASH = %1%") % printHash(hash));
|
|
||||||
|
|
||||||
Path tmpDir = createTempDir();
|
Path tmpDir = createTempDir();
|
||||||
AutoDelete delTmp(tmpDir);
|
AutoDelete delTmp(tmpDir);
|
||||||
Path hashFile = tmpDir + "/hash";
|
Path hashFile = tmpDir + "/hash";
|
||||||
|
@ -759,8 +758,6 @@ void LocalStore::exportPath(const Path & path, bool sign,
|
||||||
args.push_back(hashFile);
|
args.push_back(hashFile);
|
||||||
string signature = runProgram("openssl", true, args);
|
string signature = runProgram("openssl", true, args);
|
||||||
|
|
||||||
//printMsg(lvlError, format("SIGNATURE = %1%") % signature);
|
|
||||||
|
|
||||||
writeString(signature, hashAndWriteSink);
|
writeString(signature, hashAndWriteSink);
|
||||||
|
|
||||||
} else
|
} 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)
|
void deleteFromStore(const Path & _path, unsigned long long & bytesFreed)
|
||||||
{
|
{
|
||||||
bytesFreed = 0;
|
bytesFreed = 0;
|
||||||
|
|
|
@ -59,6 +59,8 @@ public:
|
||||||
void exportPath(const Path & path, bool sign,
|
void exportPath(const Path & path, bool sign,
|
||||||
Sink & sink);
|
Sink & sink);
|
||||||
|
|
||||||
|
Path importPath(bool requireSignature, Source & source);
|
||||||
|
|
||||||
void buildDerivations(const PathSet & drvPaths);
|
void buildDerivations(const PathSet & drvPaths);
|
||||||
|
|
||||||
void ensurePath(const Path & path);
|
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)
|
void RemoteStore::buildDerivations(const PathSet & drvPaths)
|
||||||
{
|
{
|
||||||
writeInt(wopBuildDerivations, to);
|
writeInt(wopBuildDerivations, to);
|
||||||
|
|
|
@ -47,6 +47,8 @@ public:
|
||||||
void exportPath(const Path & path, bool sign,
|
void exportPath(const Path & path, bool sign,
|
||||||
Sink & sink);
|
Sink & sink);
|
||||||
|
|
||||||
|
Path importPath(bool requireSignature, Source & source);
|
||||||
|
|
||||||
void buildDerivations(const PathSet & drvPaths);
|
void buildDerivations(const PathSet & drvPaths);
|
||||||
|
|
||||||
void ensurePath(const Path & path);
|
void ensurePath(const Path & path);
|
||||||
|
|
|
@ -99,6 +99,10 @@ public:
|
||||||
virtual void exportPath(const Path & path, bool sign,
|
virtual void exportPath(const Path & path, bool sign,
|
||||||
Sink & sink) = 0;
|
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
|
/* Ensure that the output paths of the derivation are valid. If
|
||||||
they are already valid, this is a no-op. Otherwise, validity
|
they are already valid, this is a no-op. Otherwise, validity
|
||||||
can be reached in two ways. First, if the output paths have
|
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;
|
static int counter = 0;
|
||||||
Path tmpRoot = canonPath(getEnv("TMPDIR", "/tmp"), true);
|
Path tmpRoot2 = canonPath(tmpRoot.empty() ? getEnv("TMPDIR", "/tmp") : tmpRoot, true);
|
||||||
return (format("%1%/nix-%2%-%3%") % tmpRoot % getpid() % counter++).str();
|
return (format("%1%/nix-%2%-%3%") % tmpRoot2 % getpid() % counter++).str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Path createTempDir()
|
Path createTempDir(const Path & tmpRoot)
|
||||||
{
|
{
|
||||||
while (1) {
|
while (1) {
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
Path tmpDir = tempName();
|
Path tmpDir = tempName(tmpRoot);
|
||||||
if (mkdir(tmpDir.c_str(), 0777) == 0) {
|
if (mkdir(tmpDir.c_str(), 0777) == 0) {
|
||||||
/* Explicitly set the group of the directory. This is to
|
/* Explicitly set the group of the directory. This is to
|
||||||
work around around problems caused by BSD's group
|
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);
|
void makePathReadOnly(const Path & path);
|
||||||
|
|
||||||
/* Create a temporary directory. */
|
/* Create a temporary directory. */
|
||||||
Path createTempDir();
|
Path createTempDir(const Path & tmpRoot = "");
|
||||||
|
|
||||||
/* Create a directory and all its parents, if necessary. */
|
/* Create a directory and all its parents, if necessary. */
|
||||||
void createDirs(const Path & path);
|
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. */
|
/* Initialise the Nix databases. */
|
||||||
static void opInit(Strings opFlags, Strings opArgs)
|
static void opInit(Strings opFlags, Strings opArgs)
|
||||||
{
|
{
|
||||||
|
@ -722,6 +732,8 @@ void run(Strings args)
|
||||||
op = opRestore;
|
op = opRestore;
|
||||||
else if (arg == "--export")
|
else if (arg == "--export")
|
||||||
op = opExport;
|
op = opExport;
|
||||||
|
else if (arg == "--import")
|
||||||
|
op = opImport;
|
||||||
else if (arg == "--init")
|
else if (arg == "--init")
|
||||||
op = opInit;
|
op = opInit;
|
||||||
else if (arg == "--verify")
|
else if (arg == "--verify")
|
||||||
|
|
Loading…
Reference in a new issue