diff --git a/src/cryfs-cli/Cli.cpp b/src/cryfs-cli/Cli.cpp index d3e811b5..53c4c74b 100644 --- a/src/cryfs-cli/Cli.cpp +++ b/src/cryfs-cli/Cli.cpp @@ -192,8 +192,8 @@ namespace cryfs { return *configFile; } - void Cli::_checkConfigIntegrity(const bf::path& basedir, const CryConfigFile& config, bool allowReplacedFilesystem) { - auto basedirMetadata = BasedirMetadata::load(); + void Cli::_checkConfigIntegrity(const bf::path& basedir, const LocalStateDir& localStateDir, const CryConfigFile& config, bool allowReplacedFilesystem) { + auto basedirMetadata = BasedirMetadata::load(localStateDir); if (!allowReplacedFilesystem && !basedirMetadata.filesystemIdForBasedirIsCorrect(basedir, config.config()->FilesystemId())) { if (!_console->askYesNo("The filesystem id in the config file is different to the last time we loaded a filesystem from this basedir. This can be genuine if you replaced the filesystem with a different one. If you didn't do that, it is possible that an attacker did. Do you want to continue loading the file system?", false)) { throw CryfsException( @@ -205,24 +205,24 @@ namespace cryfs { basedirMetadata.save(); } - CryConfigLoader::ConfigLoadResult Cli::_loadOrCreateConfig(const ProgramOptions &options) { + CryConfigLoader::ConfigLoadResult Cli::_loadOrCreateConfig(const ProgramOptions &options, const LocalStateDir& localStateDir) { auto configFile = _determineConfigFile(options); - auto config = _loadOrCreateConfigFile(std::move(configFile), options.cipher(), options.blocksizeBytes(), options.allowFilesystemUpgrade(), options.missingBlockIsIntegrityViolation(), options.allowReplacedFilesystem()); + auto config = _loadOrCreateConfigFile(std::move(configFile), localStateDir, options.cipher(), options.blocksizeBytes(), options.allowFilesystemUpgrade(), options.missingBlockIsIntegrityViolation(), options.allowReplacedFilesystem()); if (config == none) { throw CryfsException("Could not load config file. Did you enter the correct password?", ErrorCode::WrongPassword); } - _checkConfigIntegrity(options.baseDir(), config->configFile, options.allowReplacedFilesystem()); + _checkConfigIntegrity(options.baseDir(), localStateDir, config->configFile, options.allowReplacedFilesystem()); return std::move(*config); } - optional Cli::_loadOrCreateConfigFile(bf::path configFilePath, const optional &cipher, const optional &blocksizeBytes, bool allowFilesystemUpgrade, const optional &missingBlockIsIntegrityViolation, bool allowReplacedFilesystem) { + optional Cli::_loadOrCreateConfigFile(bf::path configFilePath, LocalStateDir localStateDir, const optional &cipher, const optional &blocksizeBytes, bool allowFilesystemUpgrade, const optional &missingBlockIsIntegrityViolation, bool allowReplacedFilesystem) { if (_noninteractive) { - return CryConfigLoader(_console, _keyGenerator, _scryptSettings, + return CryConfigLoader(_console, _keyGenerator, std::move(localStateDir), _scryptSettings, &Cli::_askPasswordNoninteractive, &Cli::_askPasswordNoninteractive, cipher, blocksizeBytes, missingBlockIsIntegrityViolation).loadOrCreate(std::move(configFilePath), allowFilesystemUpgrade, allowReplacedFilesystem); } else { - return CryConfigLoader(_console, _keyGenerator, _scryptSettings, + return CryConfigLoader(_console, _keyGenerator, std::move(localStateDir), _scryptSettings, &Cli::_askPasswordForExistingFilesystem, &Cli::_askPasswordForNewFilesystem, cipher, blocksizeBytes, missingBlockIsIntegrityViolation).loadOrCreate(std::move(configFilePath), allowFilesystemUpgrade, allowReplacedFilesystem); @@ -231,9 +231,10 @@ namespace cryfs { void Cli::_runFilesystem(const ProgramOptions &options) { try { + LocalStateDir localStateDir(Environment::localStateDir()); auto blockStore = make_unique_ref(options.baseDir()); - auto config = _loadOrCreateConfig(options); - CryDevice device(std::move(config.configFile), std::move(blockStore), config.myClientId, + auto config = _loadOrCreateConfig(options, localStateDir); + CryDevice device(std::move(config.configFile), std::move(blockStore), std::move(localStateDir), config.myClientId, options.noIntegrityChecks(), config.configFile.config()->missingBlockIsIntegrityViolation()); _sanityCheckFilesystem(&device); fspp::FilesystemImpl fsimpl(&device); diff --git a/src/cryfs-cli/Cli.h b/src/cryfs-cli/Cli.h index 5eafc34a..290eaa23 100644 --- a/src/cryfs-cli/Cli.h +++ b/src/cryfs-cli/Cli.h @@ -23,9 +23,9 @@ namespace cryfs { private: void _checkForUpdates(cpputils::unique_ref httpClient); void _runFilesystem(const program_options::ProgramOptions &options); - CryConfigLoader::ConfigLoadResult _loadOrCreateConfig(const program_options::ProgramOptions &options); - void _checkConfigIntegrity(const boost::filesystem::path& basedir, const CryConfigFile& config, bool allowReplacedFilesystem); - boost::optional _loadOrCreateConfigFile(boost::filesystem::path configFilePath, const boost::optional &cipher, const boost::optional &blocksizeBytes, bool allowFilesystemUpgrade, const boost::optional &missingBlockIsIntegrityViolation, bool allowReplacedFilesystem); + CryConfigLoader::ConfigLoadResult _loadOrCreateConfig(const program_options::ProgramOptions &options, const LocalStateDir& localStateDir); + void _checkConfigIntegrity(const boost::filesystem::path& basedir, const LocalStateDir& localStateDir, const CryConfigFile& config, bool allowReplacedFilesystem); + boost::optional _loadOrCreateConfigFile(boost::filesystem::path configFilePath, LocalStateDir localStateDir, const boost::optional &cipher, const boost::optional &blocksizeBytes, bool allowFilesystemUpgrade, const boost::optional &missingBlockIsIntegrityViolation, bool allowReplacedFilesystem); boost::filesystem::path _determineConfigFile(const program_options::ProgramOptions &options); static std::string _askPasswordForExistingFilesystem(); static std::string _askPasswordForNewFilesystem(); diff --git a/src/cryfs-cli/Environment.cpp b/src/cryfs-cli/Environment.cpp index 19166b28..441ef849 100644 --- a/src/cryfs-cli/Environment.cpp +++ b/src/cryfs-cli/Environment.cpp @@ -1,12 +1,16 @@ #include "Environment.h" #include +#include +#include using std::string; +namespace bf = boost::filesystem; namespace cryfs { const string Environment::FRONTEND_KEY = "CRYFS_FRONTEND"; const string Environment::FRONTEND_NONINTERACTIVE = "noninteractive"; const string Environment::NOUPDATECHECK_KEY = "CRYFS_NO_UPDATE_CHECK"; + const string Environment::LOCALSTATEDIR_KEY = "CRYFS_LOCAL_STATE_DIR"; bool Environment::isNoninteractive() { char *frontend = std::getenv(FRONTEND_KEY.c_str()); @@ -16,4 +20,19 @@ namespace cryfs { bool Environment::noUpdateCheck() { return nullptr != std::getenv(NOUPDATECHECK_KEY.c_str()); } + + const bf::path& Environment::defaultLocalStateDir() { + static const bf::path value = cpputils::system::HomeDirectory::get() / ".cryfs"; + return value; + } + + bf::path Environment::localStateDir() { + const char* localStateDir = std::getenv(LOCALSTATEDIR_KEY.c_str()); + + if (nullptr == localStateDir) { + return defaultLocalStateDir(); + } + + return bf::absolute(localStateDir); + } } diff --git a/src/cryfs-cli/Environment.h b/src/cryfs-cli/Environment.h index 2356e3f1..506d9877 100644 --- a/src/cryfs-cli/Environment.h +++ b/src/cryfs-cli/Environment.h @@ -3,6 +3,7 @@ #define MESSMER_CRYFS_CLI_ENVIRONMENT_H #include +#include namespace cryfs { @@ -10,10 +11,13 @@ namespace cryfs { public: static bool isNoninteractive(); static bool noUpdateCheck(); + static boost::filesystem::path localStateDir(); + static const boost::filesystem::path& defaultLocalStateDir(); static const std::string FRONTEND_KEY; static const std::string FRONTEND_NONINTERACTIVE; static const std::string NOUPDATECHECK_KEY; + static const std::string LOCALSTATEDIR_KEY; private: Environment() = delete; diff --git a/src/cryfs-cli/program_options/Parser.cpp b/src/cryfs-cli/program_options/Parser.cpp index d6a54fba..a31754f5 100644 --- a/src/cryfs-cli/program_options/Parser.cpp +++ b/src/cryfs-cli/program_options/Parser.cpp @@ -210,6 +210,11 @@ void Parser::_showHelp() { << " " << Environment::NOUPDATECHECK_KEY << "=true\n" << "\tBy default, CryFS connects to the internet to check for known\n" << "\tsecurity vulnerabilities and new versions. This option disables this.\n" + << " " << Environment::LOCALSTATEDIR_KEY << "=[path]\n" + << "\tSets the directory cryfs uses to store local state. This local state\n" + << "\tis used to recognize known file systems and run integrity checks\n" + << "\t(i.e. check that they haven't been modified by an attacker.\n" + << "\tDefault value: " << Environment::defaultLocalStateDir().c_str() << "\n" << endl; } diff --git a/src/cryfs/config/CryConfigCreator.cpp b/src/cryfs/config/CryConfigCreator.cpp index f300486d..7543ab8d 100644 --- a/src/cryfs/config/CryConfigCreator.cpp +++ b/src/cryfs/config/CryConfigCreator.cpp @@ -15,8 +15,8 @@ using boost::none; namespace cryfs { - CryConfigCreator::CryConfigCreator(shared_ptr console, RandomGenerator &encryptionKeyGenerator) - :_console(console), _configConsole(console), _encryptionKeyGenerator(encryptionKeyGenerator) { + CryConfigCreator::CryConfigCreator(shared_ptr console, RandomGenerator &encryptionKeyGenerator, LocalStateDir localStateDir) + :_console(console), _configConsole(console), _encryptionKeyGenerator(encryptionKeyGenerator), _localStateDir(std::move(localStateDir)) { } CryConfigCreator::ConfigCreateResult CryConfigCreator::create(const optional &cipherFromCommandLine, const optional &blocksizeBytesFromCommandLine, const optional &missingBlockIsIntegrityViolationFromCommandLine, bool allowReplacedFilesystem) { @@ -29,7 +29,7 @@ namespace cryfs { config.SetRootBlob(_generateRootBlobId()); config.SetFilesystemId(_generateFilesystemID()); auto encryptionKey = _generateEncKey(config.Cipher()); - auto localState = LocalStateMetadata::loadOrGenerate(LocalStateDir::forFilesystemId(config.FilesystemId()), cpputils::Data::FromString(encryptionKey), allowReplacedFilesystem); + auto localState = LocalStateMetadata::loadOrGenerate(_localStateDir.forFilesystemId(config.FilesystemId()), cpputils::Data::FromString(encryptionKey), allowReplacedFilesystem); uint32_t myClientId = localState.myClientId(); config.SetEncryptionKey(std::move(encryptionKey)); config.SetExclusiveClientId(_generateExclusiveClientId(missingBlockIsIntegrityViolationFromCommandLine, myClientId)); diff --git a/src/cryfs/config/CryConfigCreator.h b/src/cryfs/config/CryConfigCreator.h index 645d8736..df3f0496 100644 --- a/src/cryfs/config/CryConfigCreator.h +++ b/src/cryfs/config/CryConfigCreator.h @@ -5,13 +5,14 @@ #include #include #include +#include #include "CryConfig.h" #include "CryConfigConsole.h" namespace cryfs { class CryConfigCreator final { public: - CryConfigCreator(std::shared_ptr console, cpputils::RandomGenerator &encryptionKeyGenerator); + CryConfigCreator(std::shared_ptr console, cpputils::RandomGenerator &encryptionKeyGenerator, LocalStateDir localStateDir); CryConfigCreator(CryConfigCreator &&rhs) = default; struct ConfigCreateResult { @@ -32,6 +33,7 @@ namespace cryfs { std::shared_ptr _console; CryConfigConsole _configConsole; cpputils::RandomGenerator &_encryptionKeyGenerator; + LocalStateDir _localStateDir; DISALLOW_COPY_AND_ASSIGN(CryConfigCreator); }; diff --git a/src/cryfs/config/CryConfigLoader.cpp b/src/cryfs/config/CryConfigLoader.cpp index 8d751066..95151d94 100644 --- a/src/cryfs/config/CryConfigLoader.cpp +++ b/src/cryfs/config/CryConfigLoader.cpp @@ -25,11 +25,12 @@ using namespace cpputils::logging; namespace cryfs { -CryConfigLoader::CryConfigLoader(shared_ptr console, RandomGenerator &keyGenerator, const SCryptSettings &scryptSettings, function askPasswordForExistingFilesystem, function askPasswordForNewFilesystem, const optional &cipherFromCommandLine, const boost::optional &blocksizeBytesFromCommandLine, const boost::optional &missingBlockIsIntegrityViolationFromCommandLine) - : _console(console), _creator(std::move(console), keyGenerator), _scryptSettings(scryptSettings), +CryConfigLoader::CryConfigLoader(shared_ptr console, RandomGenerator &keyGenerator, LocalStateDir localStateDir, const SCryptSettings &scryptSettings, function askPasswordForExistingFilesystem, function askPasswordForNewFilesystem, const optional &cipherFromCommandLine, const boost::optional &blocksizeBytesFromCommandLine, const boost::optional &missingBlockIsIntegrityViolationFromCommandLine) + : _console(console), _creator(std::move(console), keyGenerator, localStateDir), _scryptSettings(scryptSettings), _askPasswordForExistingFilesystem(askPasswordForExistingFilesystem), _askPasswordForNewFilesystem(askPasswordForNewFilesystem), _cipherFromCommandLine(cipherFromCommandLine), _blocksizeBytesFromCommandLine(blocksizeBytesFromCommandLine), - _missingBlockIsIntegrityViolationFromCommandLine(missingBlockIsIntegrityViolationFromCommandLine) { + _missingBlockIsIntegrityViolationFromCommandLine(missingBlockIsIntegrityViolationFromCommandLine), + _localStateDir(std::move(localStateDir)) { } optional CryConfigLoader::_loadConfig(bf::path filename, bool allowFilesystemUpgrade, bool allowReplacedFilesystem) { @@ -62,7 +63,7 @@ optional CryConfigLoader::_loadConfig(bf::pat config->save(); } _checkCipher(*config->config()); - auto localState = LocalStateMetadata::loadOrGenerate(LocalStateDir::forFilesystemId(config->config()->FilesystemId()), cpputils::Data::FromString(config->config()->EncryptionKey()), allowReplacedFilesystem); + auto localState = LocalStateMetadata::loadOrGenerate(_localStateDir.forFilesystemId(config->config()->FilesystemId()), cpputils::Data::FromString(config->config()->EncryptionKey()), allowReplacedFilesystem); uint32_t myClientId = localState.myClientId(); _checkMissingBlocksAreIntegrityViolations(&*config, myClientId); return ConfigLoadResult {std::move(*config), myClientId}; diff --git a/src/cryfs/config/CryConfigLoader.h b/src/cryfs/config/CryConfigLoader.h index e739cb86..04c1c53a 100644 --- a/src/cryfs/config/CryConfigLoader.h +++ b/src/cryfs/config/CryConfigLoader.h @@ -13,7 +13,7 @@ namespace cryfs { class CryConfigLoader final { public: - CryConfigLoader(std::shared_ptr console, cpputils::RandomGenerator &keyGenerator, const cpputils::SCryptSettings &scryptSettings, std::function askPasswordForExistingFilesystem, std::function askPasswordForNewFilesystem, const boost::optional &cipherFromCommandLine, const boost::optional &blocksizeBytesFromCommandLine, const boost::optional &missingBlockIsIntegrityViolationFromCommandLine); + CryConfigLoader(std::shared_ptr console, cpputils::RandomGenerator &keyGenerator, LocalStateDir localStateDir, const cpputils::SCryptSettings &scryptSettings, std::function askPasswordForExistingFilesystem, std::function askPasswordForNewFilesystem, const boost::optional &cipherFromCommandLine, const boost::optional &blocksizeBytesFromCommandLine, const boost::optional &missingBlockIsIntegrityViolationFromCommandLine); CryConfigLoader(CryConfigLoader &&rhs) = default; struct ConfigLoadResult { @@ -38,6 +38,7 @@ private: boost::optional _cipherFromCommandLine; boost::optional _blocksizeBytesFromCommandLine; boost::optional _missingBlockIsIntegrityViolationFromCommandLine; + LocalStateDir _localStateDir; DISALLOW_COPY_AND_ASSIGN(CryConfigLoader); }; diff --git a/src/cryfs/filesystem/CryDevice.cpp b/src/cryfs/filesystem/CryDevice.cpp index bed53960..0ed95194 100644 --- a/src/cryfs/filesystem/CryDevice.cpp +++ b/src/cryfs/filesystem/CryDevice.cpp @@ -51,14 +51,14 @@ namespace bf = boost::filesystem; namespace cryfs { -CryDevice::CryDevice(CryConfigFile configFile, unique_ref blockStore, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation) -: _fsBlobStore(CreateFsBlobStore(std::move(blockStore), &configFile, myClientId, noIntegrityChecks, missingBlockIsIntegrityViolation)), +CryDevice::CryDevice(CryConfigFile configFile, unique_ref blockStore, const LocalStateDir& localStateDir, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation) +: _fsBlobStore(CreateFsBlobStore(std::move(blockStore), &configFile, localStateDir, myClientId, noIntegrityChecks, missingBlockIsIntegrityViolation)), _rootBlobId(GetOrCreateRootBlobId(&configFile)), _onFsAction() { } -unique_ref CryDevice::CreateFsBlobStore(unique_ref blockStore, CryConfigFile *configFile, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation) { - auto blobStore = CreateBlobStore(std::move(blockStore), configFile, myClientId, noIntegrityChecks, missingBlockIsIntegrityViolation); +unique_ref CryDevice::CreateFsBlobStore(unique_ref blockStore, CryConfigFile *configFile, const LocalStateDir& localStateDir, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation) { + auto blobStore = CreateBlobStore(std::move(blockStore), localStateDir, configFile, myClientId, noIntegrityChecks, missingBlockIsIntegrityViolation); #ifndef CRYFS_NO_COMPATIBILITY auto fsBlobStore = MigrateOrCreateFsBlobStore(std::move(blobStore), configFile); @@ -83,8 +83,8 @@ unique_ref CryDevice::MigrateOrCreateFsBlobStore(uniqu } #endif -unique_ref CryDevice::CreateBlobStore(unique_ref blockStore, CryConfigFile *configFile, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation) { - auto integrityEncryptedBlockStore = CreateIntegrityEncryptedBlockStore(std::move(blockStore), configFile, myClientId, noIntegrityChecks, missingBlockIsIntegrityViolation); +unique_ref CryDevice::CreateBlobStore(unique_ref blockStore, const LocalStateDir& localStateDir, CryConfigFile *configFile, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation) { + auto integrityEncryptedBlockStore = CreateIntegrityEncryptedBlockStore(std::move(blockStore), localStateDir, configFile, myClientId, noIntegrityChecks, missingBlockIsIntegrityViolation); // Create integrityEncryptedBlockStore not in the same line as BlobStoreOnBlocks, because it can modify BlocksizeBytes // in the configFile and therefore has to be run before the second parameter to the BlobStoreOnBlocks parameter is evaluated. return make_unique_ref( @@ -96,9 +96,9 @@ unique_ref CryDevice::CreateBlobStore(unique_refconfig()->BlocksizeBytes()); } -unique_ref CryDevice::CreateIntegrityEncryptedBlockStore(unique_ref blockStore, CryConfigFile *configFile, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation) { +unique_ref CryDevice::CreateIntegrityEncryptedBlockStore(unique_ref blockStore, const LocalStateDir& localStateDir, CryConfigFile *configFile, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation) { auto encryptedBlockStore = CreateEncryptedBlockStore(*configFile->config(), std::move(blockStore)); - auto statePath = LocalStateDir::forFilesystemId(configFile->config()->FilesystemId()); + auto statePath = localStateDir.forFilesystemId(configFile->config()->FilesystemId()); auto integrityFilePath = statePath / "integritydata"; #ifndef CRYFS_NO_COMPATIBILITY diff --git a/src/cryfs/filesystem/CryDevice.h b/src/cryfs/filesystem/CryDevice.h index 54b86d83..25dbd06d 100644 --- a/src/cryfs/filesystem/CryDevice.h +++ b/src/cryfs/filesystem/CryDevice.h @@ -8,6 +8,7 @@ #include #include +#include #include "parallelaccessfsblobstore/ParallelAccessFsBlobStore.h" #include "parallelaccessfsblobstore/DirBlobRef.h" @@ -18,7 +19,7 @@ namespace cryfs { class CryDevice final: public fspp::Device { public: - CryDevice(CryConfigFile config, cpputils::unique_ref blockStore, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation); + CryDevice(CryConfigFile config, cpputils::unique_ref blockStore, const LocalStateDir& localStateDir, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation); void statfs(const boost::filesystem::path &path, struct ::statvfs *fsstat) override; @@ -53,12 +54,12 @@ private: blockstore::BlockId GetOrCreateRootBlobId(CryConfigFile *config); blockstore::BlockId CreateRootBlobAndReturnId(); - static cpputils::unique_ref CreateFsBlobStore(cpputils::unique_ref blockStore, CryConfigFile *configFile, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation); + static cpputils::unique_ref CreateFsBlobStore(cpputils::unique_ref blockStore, CryConfigFile *configFile, const LocalStateDir& localStateDir, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation); #ifndef CRYFS_NO_COMPATIBILITY static cpputils::unique_ref MigrateOrCreateFsBlobStore(cpputils::unique_ref blobStore, CryConfigFile *configFile); #endif - static cpputils::unique_ref CreateBlobStore(cpputils::unique_ref blockStore, CryConfigFile *configFile, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation); - static cpputils::unique_ref CreateIntegrityEncryptedBlockStore(cpputils::unique_ref blockStore, CryConfigFile *configFile, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation); + static cpputils::unique_ref CreateBlobStore(cpputils::unique_ref blockStore, const LocalStateDir& localStateDir, CryConfigFile *configFile, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation); + static cpputils::unique_ref CreateIntegrityEncryptedBlockStore(cpputils::unique_ref blockStore, const LocalStateDir& localStateDir, CryConfigFile *configFile, uint32_t myClientId, bool noIntegrityChecks, bool missingBlockIsIntegrityViolation); static cpputils::unique_ref CreateEncryptedBlockStore(const CryConfig &config, cpputils::unique_ref baseBlockStore); struct BlobWithParent { diff --git a/src/cryfs/localstate/BasedirMetadata.cpp b/src/cryfs/localstate/BasedirMetadata.cpp index 78fab99f..5f432168 100644 --- a/src/cryfs/localstate/BasedirMetadata.cpp +++ b/src/cryfs/localstate/BasedirMetadata.cpp @@ -42,15 +42,17 @@ string jsonPathForBasedir(const bf::path &basedir) { } -BasedirMetadata::BasedirMetadata(ptree data) - :_data(data) {} +BasedirMetadata::BasedirMetadata(ptree data, bf::path filename) + :_filename(std::move(filename)), _data(std::move(data)) {} -BasedirMetadata BasedirMetadata::load() { - return BasedirMetadata(_load(LocalStateDir::forBasedirMetadata())); +BasedirMetadata BasedirMetadata::load(const LocalStateDir& localStateDir) { + auto filename = localStateDir.forBasedirMetadata(); + auto loaded = _load(filename); + return BasedirMetadata(std::move(loaded), std::move(filename)); } void BasedirMetadata::save() { - _save(LocalStateDir::forBasedirMetadata(), _data); + _save(_filename, _data); } bool BasedirMetadata::filesystemIdForBasedirIsCorrect(const bf::path &basedir, const CryConfig::FilesystemID &filesystemId) const { diff --git a/src/cryfs/localstate/BasedirMetadata.h b/src/cryfs/localstate/BasedirMetadata.h index 9cad2feb..369a7325 100644 --- a/src/cryfs/localstate/BasedirMetadata.h +++ b/src/cryfs/localstate/BasedirMetadata.h @@ -5,12 +5,13 @@ #include #include #include "../config/CryConfig.h" +#include "LocalStateDir.h" namespace cryfs { class BasedirMetadata final { public: - static BasedirMetadata load(); + static BasedirMetadata load(const LocalStateDir& localStateDir); void save(); BasedirMetadata(const BasedirMetadata&) = delete; @@ -22,8 +23,9 @@ public: BasedirMetadata& updateFilesystemIdForBasedir(const boost::filesystem::path &basedir, const CryConfig::FilesystemID &filesystemId); private: - BasedirMetadata(boost::property_tree::ptree data); + BasedirMetadata(boost::property_tree::ptree data, boost::filesystem::path filename); + boost::filesystem::path _filename; boost::property_tree::ptree _data; }; diff --git a/src/cryfs/localstate/LocalStateDir.cpp b/src/cryfs/localstate/LocalStateDir.cpp index 83c7cca4..8803ce84 100644 --- a/src/cryfs/localstate/LocalStateDir.cpp +++ b/src/cryfs/localstate/LocalStateDir.cpp @@ -1,28 +1,23 @@ #include "LocalStateDir.h" -#include #include namespace bf = boost::filesystem; namespace cryfs { - namespace { - bf::path appDir() { - return cpputils::system::HomeDirectory::get() / ".cryfs"; - } - } + LocalStateDir::LocalStateDir(bf::path appDir): _appDir(std::move(appDir)) {} - bf::path LocalStateDir::forFilesystemId(const CryConfig::FilesystemID &filesystemId) { - _createDirIfNotExists(appDir()); - bf::path filesystems_dir = appDir() / "filesystems"; + bf::path LocalStateDir::forFilesystemId(const CryConfig::FilesystemID &filesystemId) const { + _createDirIfNotExists(_appDir); + bf::path filesystems_dir = _appDir / "filesystems"; _createDirIfNotExists(filesystems_dir); bf::path this_filesystem_dir = filesystems_dir / filesystemId.ToString(); _createDirIfNotExists(this_filesystem_dir); return this_filesystem_dir; } - bf::path LocalStateDir::forBasedirMetadata() { - _createDirIfNotExists(appDir()); - return appDir() / "basedirs"; + bf::path LocalStateDir::forBasedirMetadata() const { + _createDirIfNotExists(_appDir); + return _appDir / "basedirs"; } void LocalStateDir::_createDirIfNotExists(const bf::path &path) { diff --git a/src/cryfs/localstate/LocalStateDir.h b/src/cryfs/localstate/LocalStateDir.h index 3ccf84a8..38f495e2 100644 --- a/src/cryfs/localstate/LocalStateDir.h +++ b/src/cryfs/localstate/LocalStateDir.h @@ -10,11 +10,13 @@ namespace cryfs { class LocalStateDir final { public: - static boost::filesystem::path forFilesystemId(const CryConfig::FilesystemID &filesystemId); - static boost::filesystem::path forBasedirMetadata(); + LocalStateDir(boost::filesystem::path appDir); + + boost::filesystem::path forFilesystemId(const CryConfig::FilesystemID &filesystemId) const; + boost::filesystem::path forBasedirMetadata() const; private: - LocalStateDir(); // static functions only + boost::filesystem::path _appDir; static void _createDirIfNotExists(const boost::filesystem::path &path); }; diff --git a/test/cryfs-cli/EnvironmentTest.cpp b/test/cryfs-cli/EnvironmentTest.cpp index 48126530..17459f8f 100644 --- a/test/cryfs-cli/EnvironmentTest.cpp +++ b/test/cryfs-cli/EnvironmentTest.cpp @@ -1,12 +1,15 @@ #include #include #include +#include using namespace cryfs; using std::string; using boost::optional; using boost::none; +namespace bf = boost::filesystem; + class EnvironmentTest : public ::testing::Test { public: // WithEnv sets an environment variable while it is in scope. @@ -62,3 +65,22 @@ TEST_F(EnvironmentTest, NoUpdateCheck_SetToOtherValue) { // No matter what the value is, setting the environment variable says we don't do update checks. EXPECT_TRUE(Environment::noUpdateCheck()); } + +TEST_F(EnvironmentTest, LocalStateDir_NotSet) { + EXPECT_EQ(Environment::defaultLocalStateDir(), Environment::localStateDir()); +} + +TEST_F(EnvironmentTest, LocalStateDir_Set) { + WithEnv env("CRYFS_LOCAL_STATE_DIR", "/my/local/state/dir"); + EXPECT_EQ("/my/local/state/dir", Environment::localStateDir().native()); +} + +TEST_F(EnvironmentTest, LocalStateDir_ConvertsRelativeToAbsolutePath_WithDot) { + WithEnv env("CRYFS_LOCAL_STATE_DIR", "./dir"); + EXPECT_EQ((bf::current_path() / "./dir").native(), Environment::localStateDir().native()); +} + +TEST_F(EnvironmentTest, LocalStateDir_ConvertsRelativeToAbsolutePath_WithoutDot) { + WithEnv env("CRYFS_LOCAL_STATE_DIR", "dir"); + EXPECT_EQ((bf::current_path() / "dir").native(), Environment::localStateDir().native()); +} diff --git a/test/cryfs/config/CryConfigCreatorTest.cpp b/test/cryfs/config/CryConfigCreatorTest.cpp index 7660881c..b4a30cfb 100644 --- a/test/cryfs/config/CryConfigCreatorTest.cpp +++ b/test/cryfs/config/CryConfigCreatorTest.cpp @@ -7,6 +7,7 @@ #include "../testutils/TestWithFakeHomeDirectory.h" #include #include +#include using namespace cryfs; @@ -43,12 +44,15 @@ class CryConfigCreatorTest: public ::testing::Test, TestWithFakeHomeDirectory { public: CryConfigCreatorTest() : console(make_shared()), - creator(console, cpputils::Random::PseudoRandom()), - noninteractiveCreator(make_shared(console), cpputils::Random::PseudoRandom()) { + tempLocalStateDir(), localStateDir(tempLocalStateDir.path()), + creator(console, cpputils::Random::PseudoRandom(), localStateDir), + noninteractiveCreator(make_shared(console), cpputils::Random::PseudoRandom(), localStateDir) { EXPECT_CALL(*console, ask(HasSubstr("block cipher"), _)).WillRepeatedly(ChooseAnyCipher()); EXPECT_CALL(*console, ask(HasSubstr("block size"), _)).WillRepeatedly(Return(0)); } shared_ptr console; + cpputils::TempDir tempLocalStateDir; + LocalStateDir localStateDir; CryConfigCreator creator; CryConfigCreator noninteractiveCreator; diff --git a/test/cryfs/config/CryConfigLoaderTest.cpp b/test/cryfs/config/CryConfigLoaderTest.cpp index 9d8cb6de..c66e8595 100644 --- a/test/cryfs/config/CryConfigLoaderTest.cpp +++ b/test/cryfs/config/CryConfigLoaderTest.cpp @@ -56,17 +56,17 @@ private: class CryConfigLoaderTest: public ::testing::Test, public TestWithMockConsole, TestWithFakeHomeDirectory { public: - CryConfigLoaderTest(): file(false) { + CryConfigLoaderTest(): file(false), tempLocalStateDir(), localStateDir(tempLocalStateDir.path()) { console = mockConsole(); } CryConfigLoader loader(const string &password, bool noninteractive, const optional &cipher = none) { auto askPassword = [password] { return password;}; if(noninteractive) { - return CryConfigLoader(make_shared(console), cpputils::Random::PseudoRandom(), SCrypt::TestSettings, askPassword, + return CryConfigLoader(make_shared(console), cpputils::Random::PseudoRandom(), localStateDir, SCrypt::TestSettings, askPassword, askPassword, cipher, none, none); } else { - return CryConfigLoader(console, cpputils::Random::PseudoRandom(), SCrypt::TestSettings, askPassword, + return CryConfigLoader(console, cpputils::Random::PseudoRandom(), localStateDir, SCrypt::TestSettings, askPassword, askPassword, cipher, none, none); } } @@ -100,7 +100,7 @@ public: void CreateWithEncryptionKey(const string &encKey, const string &password = "mypassword") { auto askPassword = [password] { return password;}; FakeRandomGenerator generator(Data::FromString(encKey)); - auto loader = CryConfigLoader(console, generator, SCrypt::TestSettings, askPassword, + auto loader = CryConfigLoader(console, generator, localStateDir, SCrypt::TestSettings, askPassword, askPassword, none, none, none); ASSERT_NE(boost::none, loader.loadOrCreate(file.path(), false, false)); } @@ -151,6 +151,8 @@ public: std::shared_ptr console; TempFile file; + cpputils::TempDir tempLocalStateDir; + LocalStateDir localStateDir; }; TEST_F(CryConfigLoaderTest, CreatesNewIfNotExisting) { diff --git a/test/cryfs/filesystem/CryFsTest.cpp b/test/cryfs/filesystem/CryFsTest.cpp index 33c6ea71..3b5379fd 100644 --- a/test/cryfs/filesystem/CryFsTest.cpp +++ b/test/cryfs/filesystem/CryFsTest.cpp @@ -33,38 +33,40 @@ using namespace cryfs; class CryFsTest: public Test, public TestWithMockConsole, public TestWithFakeHomeDirectory { public: - CryFsTest(): rootdir(), config(false) { + CryFsTest(): tempLocalStateDir(), localStateDir(tempLocalStateDir.path()), rootdir(), config(false) { } CryConfigFile loadOrCreateConfig() { auto askPassword = [] {return "mypassword";}; - return CryConfigLoader(make_shared(mockConsole()), Random::PseudoRandom(), SCrypt::TestSettings, askPassword, askPassword, none, none, none).loadOrCreate(config.path(), false, false).value().configFile; + return CryConfigLoader(make_shared(mockConsole()), Random::PseudoRandom(), localStateDir, SCrypt::TestSettings, askPassword, askPassword, none, none, none).loadOrCreate(config.path(), false, false).value().configFile; } unique_ref blockStore() { return make_unique_ref(rootdir.path()); } + cpputils::TempDir tempLocalStateDir; + LocalStateDir localStateDir; TempDir rootdir; TempFile config; }; TEST_F(CryFsTest, CreatedRootdirIsLoadableAfterClosing) { { - CryDevice dev(loadOrCreateConfig(), blockStore(), 0x12345678, false, false); + CryDevice dev(loadOrCreateConfig(), blockStore(), localStateDir, 0x12345678, false, false); } - CryDevice dev(loadOrCreateConfig(), blockStore(), 0x12345678, false, false); + CryDevice dev(loadOrCreateConfig(), blockStore(), localStateDir, 0x12345678, false, false); auto rootDir = dev.LoadDir(bf::path("/")); rootDir.value()->children(); } TEST_F(CryFsTest, LoadingFilesystemDoesntModifyConfigFile) { { - CryDevice dev(loadOrCreateConfig(), blockStore(), 0x12345678, false, false); + CryDevice dev(loadOrCreateConfig(), blockStore(), localStateDir, 0x12345678, false, false); } Data configAfterCreating = Data::LoadFromFile(config.path()).value(); { - CryDevice dev(loadOrCreateConfig(), blockStore(), 0x12345678, false, false); + CryDevice dev(loadOrCreateConfig(), blockStore(), localStateDir, 0x12345678, false, false); } Data configAfterLoading = Data::LoadFromFile(config.path()).value(); EXPECT_EQ(configAfterCreating, configAfterLoading); diff --git a/test/cryfs/filesystem/FileSystemTest.cpp b/test/cryfs/filesystem/FileSystemTest.cpp index fdf155f7..daf3941f 100644 --- a/test/cryfs/filesystem/FileSystemTest.cpp +++ b/test/cryfs/filesystem/FileSystemTest.cpp @@ -23,16 +23,18 @@ class CryFsTestFixture: public FileSystemTestFixture, public TestWithMockConsole public: CryFsTestFixture() // Don't create config tempfile yet - : configFile(false) {} + : tempLocalStateDir(), localStateDir(tempLocalStateDir.path()), configFile(false) {} unique_ref createDevice() override { auto blockStore = cpputils::make_unique_ref(); auto askPassword = [] {return "mypassword";}; - auto config = CryConfigLoader(make_shared(mockConsole()), Random::PseudoRandom(), SCrypt::TestSettings, askPassword, askPassword, none, none, none) + auto config = CryConfigLoader(make_shared(mockConsole()), Random::PseudoRandom(), localStateDir, SCrypt::TestSettings, askPassword, askPassword, none, none, none) .loadOrCreate(configFile.path(), false, false).value(); - return make_unique_ref(std::move(config.configFile), std::move(blockStore), config.myClientId, false, false); + return make_unique_ref(std::move(config.configFile), std::move(blockStore), localStateDir, config.myClientId, false, false); } + cpputils::TempDir tempLocalStateDir; + LocalStateDir localStateDir; cpputils::TempFile configFile; }; diff --git a/test/cryfs/filesystem/testutils/CryTestBase.h b/test/cryfs/filesystem/testutils/CryTestBase.h index f00a018b..c2012d7d 100644 --- a/test/cryfs/filesystem/testutils/CryTestBase.h +++ b/test/cryfs/filesystem/testutils/CryTestBase.h @@ -9,9 +9,9 @@ class CryTestBase : public TestWithFakeHomeDirectory { public: - CryTestBase(): _configFile(false), _device(nullptr) { + CryTestBase(): _tempLocalStateDir(), _localStateDir(_tempLocalStateDir.path()), _configFile(false), _device(nullptr) { auto fakeBlockStore = cpputils::make_unique_ref(); - _device = std::make_unique(configFile(), std::move(fakeBlockStore), 0x12345678, false, false); + _device = std::make_unique(configFile(), std::move(fakeBlockStore), _localStateDir, 0x12345678, false, false); } cryfs::CryConfigFile configFile() { @@ -27,6 +27,8 @@ public: } private: + cpputils::TempDir _tempLocalStateDir; + cryfs::LocalStateDir _localStateDir; cpputils::TempFile _configFile; std::unique_ptr _device; }; diff --git a/test/cryfs/localstate/BasedirMetadataTest.cpp b/test/cryfs/localstate/BasedirMetadataTest.cpp index 153f703d..10e21f5d 100644 --- a/test/cryfs/localstate/BasedirMetadataTest.cpp +++ b/test/cryfs/localstate/BasedirMetadataTest.cpp @@ -14,6 +14,9 @@ using FilesystemID = cryfs::CryConfig::FilesystemID ; class BasedirMetadataTest : public ::testing::Test, TestWithFakeHomeDirectory { public: + TempDir tempLocalStateDir; + cryfs::LocalStateDir localStateDir; + TempDir tempdir; bf::path basedir1; bf::path basedir2; @@ -21,7 +24,9 @@ public: const FilesystemID id2; BasedirMetadataTest() - : tempdir() + : tempLocalStateDir() + , localStateDir(tempLocalStateDir.path()) + , tempdir() , basedir1(tempdir.path() / "my/basedir") , basedir2(tempdir.path() / "my/other/basedir") , id1(FilesystemID::FromString("1491BB4932A389EE14BC7090AC772972")) @@ -35,32 +40,32 @@ public: }; TEST_F(BasedirMetadataTest, givenEmptyState_whenCalled_thenSucceeds) { - EXPECT_TRUE(BasedirMetadata::load().filesystemIdForBasedirIsCorrect(basedir1, id1)); + EXPECT_TRUE(BasedirMetadata::load(localStateDir).filesystemIdForBasedirIsCorrect(basedir1, id1)); } TEST_F(BasedirMetadataTest, givenStateWithBasedir_whenCalledForDifferentBasedir_thenSucceeds) { - BasedirMetadata::load().updateFilesystemIdForBasedir(basedir2, id1).save(); - EXPECT_TRUE(BasedirMetadata::load().filesystemIdForBasedirIsCorrect(basedir1, id1)); + BasedirMetadata::load(localStateDir).updateFilesystemIdForBasedir(basedir2, id1).save(); + EXPECT_TRUE(BasedirMetadata::load(localStateDir).filesystemIdForBasedirIsCorrect(basedir1, id1)); } TEST_F(BasedirMetadataTest, givenStateWithBasedir_whenCalledWithSameId_thenSucceeds) { - BasedirMetadata::load().updateFilesystemIdForBasedir(basedir1, id1).save(); - EXPECT_TRUE(BasedirMetadata::load().filesystemIdForBasedirIsCorrect(basedir1, id1)); + BasedirMetadata::load(localStateDir).updateFilesystemIdForBasedir(basedir1, id1).save(); + EXPECT_TRUE(BasedirMetadata::load(localStateDir).filesystemIdForBasedirIsCorrect(basedir1, id1)); } TEST_F(BasedirMetadataTest, givenStateWithBasedir_whenCalledWithDifferentId_thenFails) { - BasedirMetadata::load().updateFilesystemIdForBasedir(basedir1, id2).save(); - EXPECT_FALSE(BasedirMetadata::load().filesystemIdForBasedirIsCorrect(basedir1, id1)); + BasedirMetadata::load(localStateDir).updateFilesystemIdForBasedir(basedir1, id2).save(); + EXPECT_FALSE(BasedirMetadata::load(localStateDir).filesystemIdForBasedirIsCorrect(basedir1, id1)); } TEST_F(BasedirMetadataTest, givenStateWithUpdatedBasedir_whenCalledWithSameId_thenSucceeds) { - BasedirMetadata::load().updateFilesystemIdForBasedir(basedir1, id2).save(); - BasedirMetadata::load().updateFilesystemIdForBasedir(basedir1, id1).save(); - EXPECT_TRUE(BasedirMetadata::load().filesystemIdForBasedirIsCorrect(basedir1, id1)); + BasedirMetadata::load(localStateDir).updateFilesystemIdForBasedir(basedir1, id2).save(); + BasedirMetadata::load(localStateDir).updateFilesystemIdForBasedir(basedir1, id1).save(); + EXPECT_TRUE(BasedirMetadata::load(localStateDir).filesystemIdForBasedirIsCorrect(basedir1, id1)); } TEST_F(BasedirMetadataTest, givenStateWithUpdatedBasedir_whenCalledWithDifferentId_thenFails) { - BasedirMetadata::load().updateFilesystemIdForBasedir(basedir1, id2).save(); - BasedirMetadata::load().updateFilesystemIdForBasedir(basedir1, id1).save(); - EXPECT_FALSE(BasedirMetadata::load().filesystemIdForBasedirIsCorrect(basedir1, id2)); + BasedirMetadata::load(localStateDir).updateFilesystemIdForBasedir(basedir1, id2).save(); + BasedirMetadata::load(localStateDir).updateFilesystemIdForBasedir(basedir1, id1).save(); + EXPECT_FALSE(BasedirMetadata::load(localStateDir).filesystemIdForBasedirIsCorrect(basedir1, id2)); }