From 5d99db5376ee6c0527c57be095d74f50e71cb3c2 Mon Sep 17 00:00:00 2001 From: Valient Gough Date: Thu, 26 Apr 2012 02:18:26 +0000 Subject: [PATCH] reformat files before major edits git-svn-id: http://encfs.googlecode.com/svn/trunk@78 db9cf616-1c43-0410-9cb8-a902689de0d6 --- encfs/FileUtils.cpp | 2694 ++++++++++++++++++++++--------------------- encfs/FileUtils.h | 94 +- 2 files changed, 1395 insertions(+), 1393 deletions(-) diff --git a/encfs/FileUtils.cpp b/encfs/FileUtils.cpp index 165ce21..9e89d5d 100644 --- a/encfs/FileUtils.cpp +++ b/encfs/FileUtils.cpp @@ -103,160 +103,162 @@ const int V6SubVersion = 20100713; // add version field for boost 1.42+ struct ConfigInfo { - const char *fileName; - ConfigType type; - const char *environmentOverride; - bool (*loadFunc)(const char *fileName, - const boost::shared_ptr &config, - ConfigInfo *cfg); - bool (*saveFunc)(const char *fileName, - const boost::shared_ptr &config); - int currentSubVersion; - int defaultSubVersion; + const char *fileName; + ConfigType type; + const char *environmentOverride; + bool (*loadFunc)(const char *fileName, + const boost::shared_ptr &config, + ConfigInfo *cfg); + bool (*saveFunc)(const char *fileName, + const boost::shared_ptr &config); + int currentSubVersion; + int defaultSubVersion; } ConfigFileMapping[] = { - {".encfs6.xml", Config_V6, "ENCFS6_CONFIG", readV6Config, writeV6Config, - V6SubVersion, 0 }, - // backward compatible support for older versions - {".encfs5", Config_V5, "ENCFS5_CONFIG", readV5Config, writeV5Config, - V5SubVersion, V5SubVersionDefault }, - {".encfs4", Config_V4, NULL, readV4Config, writeV4Config, 0, 0 }, - // no longer support earlier versions - {".encfs3", Config_V3, NULL, NULL, NULL, 0, 0 }, - {".encfs2", Config_Prehistoric, NULL, NULL, NULL, 0, 0 }, - {".encfs", Config_Prehistoric, NULL, NULL, NULL, 0, 0 }, - {NULL,Config_None, NULL, NULL, NULL, 0, 0}}; + {".encfs6.xml", Config_V6, "ENCFS6_CONFIG", readV6Config, writeV6Config, + V6SubVersion, 0 }, + // backward compatible support for older versions + {".encfs5", Config_V5, "ENCFS5_CONFIG", readV5Config, writeV5Config, + V5SubVersion, V5SubVersionDefault }, + {".encfs4", Config_V4, NULL, readV4Config, writeV4Config, 0, 0 }, + // no longer support earlier versions + {".encfs3", Config_V3, NULL, NULL, NULL, 0, 0 }, + {".encfs2", Config_Prehistoric, NULL, NULL, NULL, 0, 0 }, + {".encfs", Config_Prehistoric, NULL, NULL, NULL, 0, 0 }, + {NULL,Config_None, NULL, NULL, NULL, 0, 0}}; #include "boost-versioning.h" // define serialization helpers +// TODO(vgough): eliminate entirely namespace boost { - namespace serialization - { - template - void save(Archive &ar, const EncFSConfig &cfg, - unsigned int version) - { - (void)version; - // version 20 (aka 20100613) - if (cfg.subVersion == 0) - ar << make_nvp("version", V6SubVersion); - else - ar << make_nvp("version", cfg.subVersion); +namespace serialization +{ - ar << make_nvp("creator", cfg.creator); - ar << make_nvp("cipherAlg", cfg.cipherIface); - ar << make_nvp("nameAlg", cfg.nameIface); - ar << make_nvp("keySize", cfg.keySize); - ar << make_nvp("blockSize", cfg.blockSize); - ar << make_nvp("uniqueIV", cfg.uniqueIV); - ar << make_nvp("chainedNameIV", cfg.chainedNameIV); - ar << make_nvp("externalIVChaining", cfg.externalIVChaining); - ar << make_nvp("blockMACBytes", cfg.blockMACBytes); - ar << make_nvp("blockMACRandBytes", cfg.blockMACRandBytes); - ar << make_nvp("allowHoles", cfg.allowHoles); +template +void save(Archive &ar, const EncFSConfig &cfg, + unsigned int version) +{ + (void)version; + // version 20 (aka 20100613) + if (cfg.subVersion == 0) + ar << make_nvp("version", V6SubVersion); + else + ar << make_nvp("version", cfg.subVersion); - int encodedSize = cfg.keyData.size(); - ar << make_nvp("encodedKeySize", encodedSize); - ar << make_nvp("encodedKeyData", - serial::make_binary_object(cfg.getKeyData(), encodedSize)); + ar << make_nvp("creator", cfg.creator); + ar << make_nvp("cipherAlg", cfg.cipherIface); + ar << make_nvp("nameAlg", cfg.nameIface); + ar << make_nvp("keySize", cfg.keySize); + ar << make_nvp("blockSize", cfg.blockSize); + ar << make_nvp("uniqueIV", cfg.uniqueIV); + ar << make_nvp("chainedNameIV", cfg.chainedNameIV); + ar << make_nvp("externalIVChaining", cfg.externalIVChaining); + ar << make_nvp("blockMACBytes", cfg.blockMACBytes); + ar << make_nvp("blockMACRandBytes", cfg.blockMACRandBytes); + ar << make_nvp("allowHoles", cfg.allowHoles); - // version 20080816 - int size = cfg.salt.size(); - ar << make_nvp("saltLen", size); - ar << make_nvp("saltData", - serial::make_binary_object(cfg.getSaltData(), size)); - ar << make_nvp("kdfIterations", cfg.kdfIterations); - ar << make_nvp("desiredKDFDuration", cfg.desiredKDFDuration); - } + int encodedSize = cfg.keyData.size(); + ar << make_nvp("encodedKeySize", encodedSize); + ar << make_nvp("encodedKeyData", + serial::make_binary_object(cfg.getKeyData(), encodedSize)); - template - void load(Archive &ar, EncFSConfig &cfg, unsigned int version) - { - rInfo("version = %i", version); - // TODO: figure out how to deprecate all but the first case.. - if (version == 20 || version >= 20100713) - { - rInfo("found new serialization format"); - ar >> make_nvp("version", cfg.subVersion); - } else if (version == 26800) - { - rInfo("found 20080816 version"); - cfg.subVersion = 20080816; - } else if (version == 26797) - { - rInfo("found 20080813"); - cfg.subVersion = 20080813; - } else if (version < (unsigned int)V5SubVersion) - { - rError("Invalid version %i - please fix config file", version); - } else - { - rInfo("Boost <= 1.41 compatibility mode"); - cfg.subVersion = version; - } - rInfo("subVersion = %i", cfg.subVersion); - - ar >> make_nvp("creator", cfg.creator); - ar >> make_nvp("cipherAlg", cfg.cipherIface); - ar >> make_nvp("nameAlg", cfg.nameIface); - ar >> make_nvp("keySize", cfg.keySize); - ar >> make_nvp("blockSize", cfg.blockSize); - ar >> make_nvp("uniqueIV", cfg.uniqueIV); - ar >> make_nvp("chainedNameIV", cfg.chainedNameIV); - ar >> make_nvp("externalIVChaining", cfg.externalIVChaining); - ar >> make_nvp("blockMACBytes", cfg.blockMACBytes); - ar >> make_nvp("blockMACRandBytes", cfg.blockMACRandBytes); - ar >> make_nvp("allowHoles", cfg.allowHoles); - - int encodedSize; - ar >> make_nvp("encodedKeySize", encodedSize); - rAssert(encodedSize == cfg.getCipher()->encodedKeySize()); - - unsigned char *key = new unsigned char[encodedSize]; - ar >> make_nvp("encodedKeyData", - serial::make_binary_object(key, encodedSize)); - cfg.assignKeyData(key, encodedSize); - delete[] key; - - if(cfg.subVersion >= 20080816) - { - int saltLen; - ar >> make_nvp("saltLen", saltLen); - unsigned char *salt = new unsigned char[saltLen]; - ar >> make_nvp("saltData", - serial::make_binary_object(salt, saltLen)); - cfg.assignSaltData(salt, saltLen); - delete[] salt; - - ar >> make_nvp("kdfIterations", cfg.kdfIterations); - ar >> make_nvp("desiredKDFDuration", cfg.desiredKDFDuration); - } else - { - cfg.salt.clear(); - cfg.kdfIterations = 16; - cfg.desiredKDFDuration = NormalKDFDuration; - } - } - - template - void serialize(Archive &ar, EncFSConfig &cfg, unsigned int version) - { - split_free(ar, cfg, version); - } - - template - void serialize(Archive &ar, Interface &i, const unsigned int version) - { - (void)version; - ar & make_nvp("name", i.name()); - ar & make_nvp("major", i.current()); - ar & make_nvp("minor", i.revision()); - } - } + // version 20080816 + int size = cfg.salt.size(); + ar << make_nvp("saltLen", size); + ar << make_nvp("saltData", + serial::make_binary_object(cfg.getSaltData(), size)); + ar << make_nvp("kdfIterations", cfg.kdfIterations); + ar << make_nvp("desiredKDFDuration", cfg.desiredKDFDuration); } +template +void load(Archive &ar, EncFSConfig &cfg, unsigned int version) +{ + rInfo("version = %i", version); + // TODO: figure out how to deprecate all but the first case.. + if (version == 20 || version >= 20100713) + { + rInfo("found new serialization format"); + ar >> make_nvp("version", cfg.subVersion); + } else if (version == 26800) + { + rInfo("found 20080816 version"); + cfg.subVersion = 20080816; + } else if (version == 26797) + { + rInfo("found 20080813"); + cfg.subVersion = 20080813; + } else if (version < (unsigned int)V5SubVersion) + { + rError("Invalid version %i - please fix config file", version); + } else + { + rInfo("Boost <= 1.41 compatibility mode"); + cfg.subVersion = version; + } + rInfo("subVersion = %i", cfg.subVersion); + + ar >> make_nvp("creator", cfg.creator); + ar >> make_nvp("cipherAlg", cfg.cipherIface); + ar >> make_nvp("nameAlg", cfg.nameIface); + ar >> make_nvp("keySize", cfg.keySize); + ar >> make_nvp("blockSize", cfg.blockSize); + ar >> make_nvp("uniqueIV", cfg.uniqueIV); + ar >> make_nvp("chainedNameIV", cfg.chainedNameIV); + ar >> make_nvp("externalIVChaining", cfg.externalIVChaining); + ar >> make_nvp("blockMACBytes", cfg.blockMACBytes); + ar >> make_nvp("blockMACRandBytes", cfg.blockMACRandBytes); + ar >> make_nvp("allowHoles", cfg.allowHoles); + + int encodedSize; + ar >> make_nvp("encodedKeySize", encodedSize); + rAssert(encodedSize == cfg.getCipher()->encodedKeySize()); + + unsigned char *key = new unsigned char[encodedSize]; + ar >> make_nvp("encodedKeyData", + serial::make_binary_object(key, encodedSize)); + cfg.assignKeyData(key, encodedSize); + delete[] key; + + if(cfg.subVersion >= 20080816) + { + int saltLen; + ar >> make_nvp("saltLen", saltLen); + unsigned char *salt = new unsigned char[saltLen]; + ar >> make_nvp("saltData", + serial::make_binary_object(salt, saltLen)); + cfg.assignSaltData(salt, saltLen); + delete[] salt; + + ar >> make_nvp("kdfIterations", cfg.kdfIterations); + ar >> make_nvp("desiredKDFDuration", cfg.desiredKDFDuration); + } else + { + cfg.salt.clear(); + cfg.kdfIterations = 16; + cfg.desiredKDFDuration = NormalKDFDuration; + } +} + +template +void serialize(Archive &ar, EncFSConfig &cfg, unsigned int version) +{ + split_free(ar, cfg, version); +} + +template +void serialize(Archive &ar, Interface &i, const unsigned int version) +{ + (void)version; + ar & make_nvp("name", i.name()); + ar & make_nvp("major", i.current()); + ar & make_nvp("minor", i.revision()); +} +} // namespace serialization +} // namespace boost + EncFS_Root::EncFS_Root() { } @@ -268,50 +270,50 @@ EncFS_Root::~EncFS_Root() bool fileExists( const char * fileName ) { - struct stat buf; - if(!lstat( fileName, &buf )) - { - return true; - } else - { - // XXX show perror? - return false; - } + struct stat buf; + if(!lstat( fileName, &buf )) + { + return true; + } else + { + // XXX show perror? + return false; + } } bool isDirectory( const char *fileName ) { - struct stat buf; - if( !lstat( fileName, &buf )) - { - return S_ISDIR( buf.st_mode ); - } else - { - return false; - } + struct stat buf; + if( !lstat( fileName, &buf )) + { + return S_ISDIR( buf.st_mode ); + } else + { + return false; + } } bool isAbsolutePath( const char *fileName ) { - if(fileName && fileName[0] != '\0' && fileName[0] == '/') - return true; - else - return false; + if(fileName && fileName[0] != '\0' && fileName[0] == '/') + return true; + else + return false; } const char *lastPathElement( const char *name ) { - const char *loc = strrchr( name, '/' ); - return loc ? loc + 1 : name; + const char *loc = strrchr( name, '/' ); + return loc ? loc + 1 : name; } std::string parentDirectory( const std::string &path ) { - size_t last = path.find_last_of( '/' ); - if(last == string::npos) - return string(""); - else - return path.substr(0, last); + size_t last = path.find_last_of( '/' ); + if(last == string::npos) + return string(""); + else + return path.substr(0, last); } bool userAllowMkdir(const char *path, mode_t mode ) @@ -321,1408 +323,1408 @@ bool userAllowMkdir(const char *path, mode_t mode ) bool userAllowMkdir(int promptno, const char *path, mode_t mode ) { - // TODO: can we internationalize the y/n names? Seems strange to prompt in - // their own language but then have to respond 'y' or 'n'. - // xgroup(setup) - cerr << autosprintf( _("The directory \"%s\" does not exist. Should it be created? (y,n) "), path ); - char answer[10]; - char *res; + // TODO: can we internationalize the y/n names? Seems strange to prompt in + // their own language but then have to respond 'y' or 'n'. + // xgroup(setup) + cerr << autosprintf( _("The directory \"%s\" does not exist. Should it be created? (y,n) "), path ); + char answer[10]; + char *res; - switch (promptno) - { - case 1: - cerr << endl << "$PROMPT$ create_root_dir" << endl; - break; - case 2: - cerr << endl << "$PROMPT$ create_mount_point" << endl; - break; - default: - break; - } - res = fgets( answer, sizeof(answer), stdin ); + switch (promptno) + { + case 1: + cerr << endl << "$PROMPT$ create_root_dir" << endl; + break; + case 2: + cerr << endl << "$PROMPT$ create_mount_point" << endl; + break; + default: + break; + } + res = fgets( answer, sizeof(answer), stdin ); - if(res != 0 && toupper(answer[0]) == 'Y') + if(res != 0 && toupper(answer[0]) == 'Y') + { + int result = mkdir( path, mode ); + if(result < 0) { - int result = mkdir( path, mode ); - if(result < 0) - { - perror( _("Unable to create directory: ") ); - return false; - } else - return true; + perror( _("Unable to create directory: ") ); + return false; } else - { - // Directory not created, by user request - cerr << _("Directory not created.") << "\n"; - return false; - } + return true; + } else + { + // Directory not created, by user request + cerr << _("Directory not created.") << "\n"; + return false; + } } ConfigType readConfig_load( ConfigInfo *nm, const char *path, - const boost::shared_ptr &config ) + const boost::shared_ptr &config ) { - if( nm->loadFunc ) + if( nm->loadFunc ) + { + try { - try - { - if( (*nm->loadFunc)( path, config, nm )) - { - config->cfgType = nm->type; - return nm->type; - } - } catch( rlog::Error & err ) - { - err.log( _RLWarningChannel ); - } - - rError( _("Found config file %s, but failed to load"), path); - return Config_None; - } else - { - // No load function - must be an unsupported type.. + if( (*nm->loadFunc)( path, config, nm )) + { config->cfgType = nm->type; - return nm->type; + return nm->type; + } + } catch( rlog::Error & err ) + { + err.log( _RLWarningChannel ); } + + rError( _("Found config file %s, but failed to load"), path); + return Config_None; + } else + { + // No load function - must be an unsupported type.. + config->cfgType = nm->type; + return nm->type; + } } ConfigType readConfig( const string &rootDir, - const boost::shared_ptr &config ) + const boost::shared_ptr &config ) { - ConfigInfo *nm = ConfigFileMapping; - while(nm->fileName) + ConfigInfo *nm = ConfigFileMapping; + while(nm->fileName) + { + // allow environment variable to override default config path + if( nm->environmentOverride != NULL ) { - // allow environment variable to override default config path - if( nm->environmentOverride != NULL ) - { - char *envFile = getenv( nm->environmentOverride ); - if( envFile != NULL ) - return readConfig_load( nm, envFile, config ); - } - // the standard place to look is in the root directory - string path = rootDir + nm->fileName; - if( fileExists( path.c_str() ) ) - return readConfig_load( nm, path.c_str(), config); - - ++nm; + char *envFile = getenv( nm->environmentOverride ); + if( envFile != NULL ) + return readConfig_load( nm, envFile, config ); } + // the standard place to look is in the root directory + string path = rootDir + nm->fileName; + if( fileExists( path.c_str() ) ) + return readConfig_load( nm, path.c_str(), config); - return Config_None; + ++nm; + } + + return Config_None; } bool readV6Config( const char *configFile, - const boost::shared_ptr &config, - ConfigInfo *info) + const boost::shared_ptr &config, + ConfigInfo *info) { - (void)info; + (void)info; - fs::ifstream st( configFile ); - if(st.is_open()) + fs::ifstream st( configFile ); + if(st.is_open()) + { + try { - try - { - boost::archive::xml_iarchive ia( st ); - ia >> BOOST_SERIALIZATION_NVP( *config ); - - return true; - } catch(boost::archive::archive_exception &e) - { - rError("Archive exception: %s", e.what()); - return false; - } - } else + boost::archive::xml_iarchive ia( st ); + ia >> BOOST_SERIALIZATION_NVP( *config ); + + return true; + } catch(boost::archive::archive_exception &e) { - rInfo("Failed to load config file %s", configFile); - return false; + rError("Archive exception: %s", e.what()); + return false; } + } else + { + rInfo("Failed to load config file %s", configFile); + return false; + } } bool readV5Config( const char *configFile, - const boost::shared_ptr &config, - ConfigInfo *info) + const boost::shared_ptr &config, + ConfigInfo *info) { - bool ok = false; + bool ok = false; - // use Config to parse the file and query it.. - ConfigReader cfgRdr; - if(cfgRdr.load( configFile )) + // use Config to parse the file and query it.. + ConfigReader cfgRdr; + if(cfgRdr.load( configFile )) + { + try { - try - { - config->subVersion = cfgRdr["subVersion"].readInt( - info->defaultSubVersion ); - if(config->subVersion > info->currentSubVersion) - { - /* config file specifies a version outside our supported - range.. */ - rWarning(_("Config subversion %i found, but this version of" - " encfs only supports up to version %i."), - config->subVersion, info->currentSubVersion); - return false; - } - if( config->subVersion < 20040813 ) - { - rError(_("This version of EncFS doesn't support " - "filesystems created before 2004-08-13")); - return false; - } + config->subVersion = cfgRdr["subVersion"].readInt( + info->defaultSubVersion ); + if(config->subVersion > info->currentSubVersion) + { + /* config file specifies a version outside our supported + range.. */ + rWarning(_("Config subversion %i found, but this version of" + " encfs only supports up to version %i."), + config->subVersion, info->currentSubVersion); + return false; + } + if( config->subVersion < 20040813 ) + { + rError(_("This version of EncFS doesn't support " + "filesystems created before 2004-08-13")); + return false; + } - cfgRdr["creator"] >> config->creator; - cfgRdr["cipher"] >> config->cipherIface; - cfgRdr["naming"] >> config->nameIface; - cfgRdr["keySize"] >> config->keySize; - cfgRdr["blockSize"] >> config->blockSize; + cfgRdr["creator"] >> config->creator; + cfgRdr["cipher"] >> config->cipherIface; + cfgRdr["naming"] >> config->nameIface; + cfgRdr["keySize"] >> config->keySize; + cfgRdr["blockSize"] >> config->blockSize; - string data; - cfgRdr["keyData"] >> data; - config->assignKeyData(data); - config->uniqueIV = cfgRdr["uniqueIV"].readBool( false ); - config->chainedNameIV = cfgRdr["chainedIV"].readBool( false ); - config->externalIVChaining = cfgRdr["externalIV"].readBool( false ); - config->blockMACBytes = cfgRdr["blockMACBytes"].readInt(0); - config->blockMACRandBytes = - cfgRdr["blockMACRandBytes"].readInt(0); + string data; + cfgRdr["keyData"] >> data; + config->assignKeyData(data); + config->uniqueIV = cfgRdr["uniqueIV"].readBool( false ); + config->chainedNameIV = cfgRdr["chainedIV"].readBool( false ); + config->externalIVChaining = cfgRdr["externalIV"].readBool( false ); + config->blockMACBytes = cfgRdr["blockMACBytes"].readInt(0); + config->blockMACRandBytes = + cfgRdr["blockMACRandBytes"].readInt(0); - ok = true; - } catch( rlog::Error &err) - { - err.log( _RLWarningChannel ); - rDebug("Error parsing data in config file %s", configFile); - ok = false; - } + ok = true; + } catch( rlog::Error &err) + { + err.log( _RLWarningChannel ); + rDebug("Error parsing data in config file %s", configFile); + ok = false; } + } - return ok; + return ok; } bool readV4Config( const char *configFile, - const boost::shared_ptr &config, - ConfigInfo *info) + const boost::shared_ptr &config, + ConfigInfo *info) { - bool ok = false; + bool ok = false; - // use Config to parse the file and query it.. - ConfigReader cfgRdr; - if(cfgRdr.load( configFile )) + // use Config to parse the file and query it.. + ConfigReader cfgRdr; + if(cfgRdr.load( configFile )) + { + try { - try - { - cfgRdr["cipher"] >> config->cipherIface; - cfgRdr["keySize"] >> config->keySize; - cfgRdr["blockSize"] >> config->blockSize; - string data; - cfgRdr["keyData"] >> data; - config->assignKeyData(data); + cfgRdr["cipher"] >> config->cipherIface; + cfgRdr["keySize"] >> config->keySize; + cfgRdr["blockSize"] >> config->blockSize; + string data; + cfgRdr["keyData"] >> data; + config->assignKeyData(data); - // fill in default for V4 - config->nameIface = Interface("nameio/stream", 1, 0, 0); - config->creator = "EncFS 1.0.x"; - config->subVersion = info->defaultSubVersion; - config->blockMACBytes = 0; - config->blockMACRandBytes = 0; - config->uniqueIV = false; - config->externalIVChaining = false; - config->chainedNameIV = false; + // fill in default for V4 + config->nameIface = Interface("nameio/stream", 1, 0, 0); + config->creator = "EncFS 1.0.x"; + config->subVersion = info->defaultSubVersion; + config->blockMACBytes = 0; + config->blockMACRandBytes = 0; + config->uniqueIV = false; + config->externalIVChaining = false; + config->chainedNameIV = false; - ok = true; - } catch( rlog::Error &err) - { - err.log( _RLWarningChannel ); - rDebug("Error parsing config file %s", configFile); - ok = false; - } + ok = true; + } catch( rlog::Error &err) + { + err.log( _RLWarningChannel ); + rDebug("Error parsing config file %s", configFile); + ok = false; } + } - return ok; + return ok; } bool saveConfig( ConfigType type, const string &rootDir, - const boost::shared_ptr &config ) + const boost::shared_ptr &config ) { - bool ok = false; + bool ok = false; - ConfigInfo *nm = ConfigFileMapping; - while(nm->fileName) + ConfigInfo *nm = ConfigFileMapping; + while(nm->fileName) + { + if( nm->type == type && nm->saveFunc ) { - if( nm->type == type && nm->saveFunc ) - { - string path = rootDir + nm->fileName; - if( nm->environmentOverride != NULL ) - { - // use environment file if specified.. - const char *envFile = getenv( nm->environmentOverride ); - if( envFile != NULL ) - path.assign( envFile ); - } + string path = rootDir + nm->fileName; + if( nm->environmentOverride != NULL ) + { + // use environment file if specified.. + const char *envFile = getenv( nm->environmentOverride ); + if( envFile != NULL ) + path.assign( envFile ); + } - try - { - ok = (*nm->saveFunc)( path.c_str(), config ); - } catch( rlog::Error &err ) - { - err.log( _RLWarningChannel ); - ok = false; - } - break; - } - ++nm; + try + { + ok = (*nm->saveFunc)( path.c_str(), config ); + } catch( rlog::Error &err ) + { + err.log( _RLWarningChannel ); + ok = false; + } + break; } + ++nm; + } - return ok; + return ok; } bool writeV6Config( const char *configFile, - const boost::shared_ptr &config ) + const boost::shared_ptr &config ) { - fs::ofstream st( configFile ); - if(!st.is_open()) - return false; + fs::ofstream st( configFile ); + if(!st.is_open()) + return false; - st << *config; - return true; + st << *config; + return true; } std::ostream &operator << (std::ostream &st, const EncFSConfig &cfg) { - boost::archive::xml_oarchive oa(st); - oa << BOOST_SERIALIZATION_NVP( cfg ); + boost::archive::xml_oarchive oa(st); + oa << BOOST_SERIALIZATION_NVP( cfg ); - return st; + return st; } std::istream &operator >> (std::istream &st, EncFSConfig &cfg) { - boost::archive::xml_iarchive ia(st); - ia >> BOOST_SERIALIZATION_NVP( cfg ); + boost::archive::xml_iarchive ia(st); + ia >> BOOST_SERIALIZATION_NVP( cfg ); - return st; + return st; } bool writeV5Config( const char *configFile, - const boost::shared_ptr &config ) + const boost::shared_ptr &config ) { - ConfigReader cfg; + ConfigReader cfg; - cfg["creator"] << config->creator; - cfg["subVersion"] << config->subVersion; - cfg["cipher"] << config->cipherIface; - cfg["naming"] << config->nameIface; - cfg["keySize"] << config->keySize; - cfg["blockSize"] << config->blockSize; - string key; - key.assign((char *)config->getKeyData(), config->keyData.size()); - cfg["keyData"] << key; - cfg["blockMACBytes"] << config->blockMACBytes; - cfg["blockMACRandBytes"] << config->blockMACRandBytes; - cfg["uniqueIV"] << config->uniqueIV; - cfg["chainedIV"] << config->chainedNameIV; - cfg["externalIV"] << config->externalIVChaining; + cfg["creator"] << config->creator; + cfg["subVersion"] << config->subVersion; + cfg["cipher"] << config->cipherIface; + cfg["naming"] << config->nameIface; + cfg["keySize"] << config->keySize; + cfg["blockSize"] << config->blockSize; + string key; + key.assign((char *)config->getKeyData(), config->keyData.size()); + cfg["keyData"] << key; + cfg["blockMACBytes"] << config->blockMACBytes; + cfg["blockMACRandBytes"] << config->blockMACRandBytes; + cfg["uniqueIV"] << config->uniqueIV; + cfg["chainedIV"] << config->chainedNameIV; + cfg["externalIV"] << config->externalIVChaining; - return cfg.save( configFile ); + return cfg.save( configFile ); } bool writeV4Config( const char *configFile, - const boost::shared_ptr &config ) + const boost::shared_ptr &config ) { - ConfigReader cfg; + ConfigReader cfg; - cfg["cipher"] << config->cipherIface; - cfg["keySize"] << config->keySize; - cfg["blockSize"] << config->blockSize; - string key; - key.assign((char *)config->getKeyData(), config->keyData.size()); - cfg["keyData"] << key; + cfg["cipher"] << config->cipherIface; + cfg["keySize"] << config->keySize; + cfg["blockSize"] << config->blockSize; + string key; + key.assign((char *)config->getKeyData(), config->keyData.size()); + cfg["keyData"] << key; - return cfg.save( configFile ); + return cfg.save( configFile ); } static Cipher::CipherAlgorithm findCipherAlgorithm(const char *name, - int keySize ) + int keySize ) { - Cipher::AlgorithmList algorithms = Cipher::GetAlgorithmList(); - Cipher::AlgorithmList::const_iterator it; - for(it = algorithms.begin(); it != algorithms.end(); ++it) + Cipher::AlgorithmList algorithms = Cipher::GetAlgorithmList(); + Cipher::AlgorithmList::const_iterator it; + for(it = algorithms.begin(); it != algorithms.end(); ++it) + { + if( !strcmp( name, it->name.c_str() ) + && it->keyLength.allowed( keySize )) { - if( !strcmp( name, it->name.c_str() ) - && it->keyLength.allowed( keySize )) - { - return *it; - } + return *it; } + } - Cipher::CipherAlgorithm result; - return result; + Cipher::CipherAlgorithm result; + return result; } static Cipher::CipherAlgorithm selectCipherAlgorithm() { - for(;;) + for(;;) + { + // figure out what cipher they want to use.. + // xgroup(setup) + cout << _("The following cipher algorithms are available:") << "\n"; + Cipher::AlgorithmList algorithms = Cipher::GetAlgorithmList(); + Cipher::AlgorithmList::const_iterator it; + int optNum = 1; + for(it = algorithms.begin(); it != algorithms.end(); ++it, ++optNum) { - // figure out what cipher they want to use.. - // xgroup(setup) - cout << _("The following cipher algorithms are available:") << "\n"; - Cipher::AlgorithmList algorithms = Cipher::GetAlgorithmList(); - Cipher::AlgorithmList::const_iterator it; - int optNum = 1; - for(it = algorithms.begin(); it != algorithms.end(); ++it, ++optNum) - { - cout << optNum << ". " << it->name - << " : " << gettext(it->description.c_str()) << "\n"; - if(it->keyLength.min() == it->keyLength.max()) - { - // shown after algorithm name and description. - // xgroup(setup) - cout << autosprintf(_(" -- key length %i bits") - , it->keyLength.min()) << "\n"; - } else - { - cout << autosprintf( - // shown after algorithm name and description. - // xgroup(setup) - _(" -- Supports key lengths of %i to %i bits"), - it->keyLength.min(), it->keyLength.max()) << "\n"; - } + cout << optNum << ". " << it->name + << " : " << gettext(it->description.c_str()) << "\n"; + if(it->keyLength.min() == it->keyLength.max()) + { + // shown after algorithm name and description. + // xgroup(setup) + cout << autosprintf(_(" -- key length %i bits") + , it->keyLength.min()) << "\n"; + } else + { + cout << autosprintf( + // shown after algorithm name and description. + // xgroup(setup) + _(" -- Supports key lengths of %i to %i bits"), + it->keyLength.min(), it->keyLength.max()) << "\n"; + } - if(it->blockSize.min() == it->blockSize.max()) - { - cout << autosprintf( - // shown after algorithm name and description. - // xgroup(setup) - _(" -- block size %i bytes"), it->blockSize.min()) - << "\n"; - } else - { - cout << autosprintf( - // shown after algorithm name and description. - // xgroup(setup) - _(" -- Supports block sizes of %i to %i bytes"), - it->blockSize.min(), it->blockSize.max()) << "\n"; - } - } - - // xgroup(setup) - cout << "\n" << _("Enter the number corresponding to your choice: "); - char answer[10]; - char *res = fgets( answer, sizeof(answer), stdin ); - int cipherNum = (res == 0 ? 0 : atoi( answer )); - cout << "\n"; - - if( cipherNum < 1 || cipherNum > (int)algorithms.size() ) - { - cerr << _("Invalid selection.") << "\n"; - continue; - } - - it = algorithms.begin(); - while(--cipherNum) // numbering starts at 1 - ++it; - - Cipher::CipherAlgorithm alg = *it; - - // xgroup(setup) - cout << autosprintf(_("Selected algorithm \"%s\""), alg.name.c_str()) - << "\n\n"; - - return alg; + if(it->blockSize.min() == it->blockSize.max()) + { + cout << autosprintf( + // shown after algorithm name and description. + // xgroup(setup) + _(" -- block size %i bytes"), it->blockSize.min()) + << "\n"; + } else + { + cout << autosprintf( + // shown after algorithm name and description. + // xgroup(setup) + _(" -- Supports block sizes of %i to %i bytes"), + it->blockSize.min(), it->blockSize.max()) << "\n"; + } } + + // xgroup(setup) + cout << "\n" << _("Enter the number corresponding to your choice: "); + char answer[10]; + char *res = fgets( answer, sizeof(answer), stdin ); + int cipherNum = (res == 0 ? 0 : atoi( answer )); + cout << "\n"; + + if( cipherNum < 1 || cipherNum > (int)algorithms.size() ) + { + cerr << _("Invalid selection.") << "\n"; + continue; + } + + it = algorithms.begin(); + while(--cipherNum) // numbering starts at 1 + ++it; + + Cipher::CipherAlgorithm alg = *it; + + // xgroup(setup) + cout << autosprintf(_("Selected algorithm \"%s\""), alg.name.c_str()) + << "\n\n"; + + return alg; + } } static Interface selectNameCoding() { - for(;;) + for(;;) + { + // figure out what cipher they want to use.. + // xgroup(setup) + cout << _("The following filename encoding algorithms are available:") + << "\n"; + NameIO::AlgorithmList algorithms = NameIO::GetAlgorithmList(); + NameIO::AlgorithmList::const_iterator it; + int optNum = 1; + for(it = algorithms.begin(); it != algorithms.end(); ++it, ++optNum) { - // figure out what cipher they want to use.. - // xgroup(setup) - cout << _("The following filename encoding algorithms are available:") - << "\n"; - NameIO::AlgorithmList algorithms = NameIO::GetAlgorithmList(); - NameIO::AlgorithmList::const_iterator it; - int optNum = 1; - for(it = algorithms.begin(); it != algorithms.end(); ++it, ++optNum) - { - cout << optNum << ". " << it->name - << " : " << gettext(it->description.c_str()) << "\n"; - } - - // xgroup(setup) - cout << "\n" << _("Enter the number corresponding to your choice: "); - char answer[10]; - char *res = fgets( answer, sizeof(answer), stdin ); - int algNum = (res == 0 ? 0 : atoi( answer )); - cout << "\n"; - - if( algNum < 1 || algNum > (int)algorithms.size() ) - { - cerr << _("Invalid selection.") << "\n"; - continue; - } - - it = algorithms.begin(); - while(--algNum) // numbering starts at 1 - ++it; - - // xgroup(setup) - cout << autosprintf(_("Selected algorithm \"%s\""), it->name.c_str()) - << "\"\n\n"; - - return it->iface; + cout << optNum << ". " << it->name + << " : " << gettext(it->description.c_str()) << "\n"; } + + // xgroup(setup) + cout << "\n" << _("Enter the number corresponding to your choice: "); + char answer[10]; + char *res = fgets( answer, sizeof(answer), stdin ); + int algNum = (res == 0 ? 0 : atoi( answer )); + cout << "\n"; + + if( algNum < 1 || algNum > (int)algorithms.size() ) + { + cerr << _("Invalid selection.") << "\n"; + continue; + } + + it = algorithms.begin(); + while(--algNum) // numbering starts at 1 + ++it; + + // xgroup(setup) + cout << autosprintf(_("Selected algorithm \"%s\""), it->name.c_str()) + << "\"\n\n"; + + return it->iface; + } } static int selectKeySize( const Cipher::CipherAlgorithm &alg ) { - if(alg.keyLength.min() == alg.keyLength.max()) + if(alg.keyLength.min() == alg.keyLength.max()) + { + cout << autosprintf(_("Using key size of %i bits"), + alg.keyLength.min()) << "\n"; + return alg.keyLength.min(); + } + + cout << autosprintf( + // xgroup(setup) + _("Please select a key size in bits. The cipher you have chosen\n" + "supports sizes from %i to %i bits in increments of %i bits.\n" + "For example: "), alg.keyLength.min(), alg.keyLength.max(), + alg.keyLength.inc()) << "\n"; + + int numAvail = (alg.keyLength.max() - alg.keyLength.min()) + / alg.keyLength.inc(); + + if(numAvail < 5) + { + // show them all + for(int i=0; i<=numAvail; ++i) { - cout << autosprintf(_("Using key size of %i bits"), - alg.keyLength.min()) << "\n"; - return alg.keyLength.min(); + if(i) + cout << ", "; + cout << alg.keyLength.min() + i * alg.keyLength.inc(); } - - cout << autosprintf( - // xgroup(setup) - _("Please select a key size in bits. The cipher you have chosen\n" - "supports sizes from %i to %i bits in increments of %i bits.\n" - "For example: "), alg.keyLength.min(), alg.keyLength.max(), - alg.keyLength.inc()) << "\n"; - - int numAvail = (alg.keyLength.max() - alg.keyLength.min()) - / alg.keyLength.inc(); - - if(numAvail < 5) + } else + { + // partial + for(int i=0; i<3; ++i) { - // show them all - for(int i=0; i<=numAvail; ++i) - { - if(i) - cout << ", "; - cout << alg.keyLength.min() + i * alg.keyLength.inc(); - } - } else - { - // partial - for(int i=0; i<3; ++i) - { - if(i) - cout << ", "; - cout << alg.keyLength.min() + i * alg.keyLength.inc(); - } - cout << " ... " << alg.keyLength.max() - alg.keyLength.inc(); - cout << ", " << alg.keyLength.max(); + if(i) + cout << ", "; + cout << alg.keyLength.min() + i * alg.keyLength.inc(); } - // xgroup(setup) - cout << "\n" << _("Selected key size: "); + cout << " ... " << alg.keyLength.max() - alg.keyLength.inc(); + cout << ", " << alg.keyLength.max(); + } + // xgroup(setup) + cout << "\n" << _("Selected key size: "); - char answer[10]; - char *res = fgets( answer, sizeof(answer), stdin ); - int keySize = (res == 0 ? 0 : atoi( answer )); - cout << "\n"; + char answer[10]; + char *res = fgets( answer, sizeof(answer), stdin ); + int keySize = (res == 0 ? 0 : atoi( answer )); + cout << "\n"; - keySize = alg.keyLength.closest( keySize ); + keySize = alg.keyLength.closest( keySize ); - // xgroup(setup) - cout << autosprintf(_("Using key size of %i bits"), keySize) << "\n\n"; + // xgroup(setup) + cout << autosprintf(_("Using key size of %i bits"), keySize) << "\n\n"; - return keySize; + return keySize; } static int selectBlockSize( const Cipher::CipherAlgorithm &alg ) { - if(alg.blockSize.min() == alg.blockSize.max()) - { - cout << autosprintf( - // xgroup(setup) - _("Using filesystem block size of %i bytes"), - alg.blockSize.min()) << "\n"; - return alg.blockSize.min(); - } - + if(alg.blockSize.min() == alg.blockSize.max()) + { cout << autosprintf( - // xgroup(setup) - _("Select a block size in bytes. The cipher you have chosen\n" - "supports sizes from %i to %i bytes in increments of %i.\n" - "Or just hit enter for the default (%i bytes)\n"), - alg.blockSize.min(), alg.blockSize.max(), alg.blockSize.inc(), - DefaultBlockSize); + // xgroup(setup) + _("Using filesystem block size of %i bytes"), + alg.blockSize.min()) << "\n"; + return alg.blockSize.min(); + } - // xgroup(setup) - cout << "\n" << _("filesystem block size: "); - - int blockSize = DefaultBlockSize; - char answer[10]; - char *res = fgets( answer, sizeof(answer), stdin ); - cout << "\n"; + cout << autosprintf( + // xgroup(setup) + _("Select a block size in bytes. The cipher you have chosen\n" + "supports sizes from %i to %i bytes in increments of %i.\n" + "Or just hit enter for the default (%i bytes)\n"), + alg.blockSize.min(), alg.blockSize.max(), alg.blockSize.inc(), + DefaultBlockSize); - if( res != 0 && atoi( answer ) >= alg.blockSize.min() ) - blockSize = atoi( answer ); + // xgroup(setup) + cout << "\n" << _("filesystem block size: "); - blockSize = alg.blockSize.closest( blockSize ); + int blockSize = DefaultBlockSize; + char answer[10]; + char *res = fgets( answer, sizeof(answer), stdin ); + cout << "\n"; - // xgroup(setup) - cout << autosprintf(_("Using filesystem block size of %i bytes"), - blockSize) << "\n\n"; + if( res != 0 && atoi( answer ) >= alg.blockSize.min() ) + blockSize = atoi( answer ); - return blockSize; + blockSize = alg.blockSize.closest( blockSize ); + + // xgroup(setup) + cout << autosprintf(_("Using filesystem block size of %i bytes"), + blockSize) << "\n\n"; + + return blockSize; } static bool boolDefaultNo(const char *prompt) { - cout << prompt << "\n"; - cout << _("The default here is No.\n" - "Any response that does not begin with 'y' will mean No: "); + cout << prompt << "\n"; + cout << _("The default here is No.\n" + "Any response that does not begin with 'y' will mean No: "); - char answer[10]; - char *res = fgets( answer, sizeof(answer), stdin ); - cout << "\n"; + char answer[10]; + char *res = fgets( answer, sizeof(answer), stdin ); + cout << "\n"; - if(res != 0 && tolower(answer[0]) == 'y') - return true; - else - return false; + if(res != 0 && tolower(answer[0]) == 'y') + return true; + else + return false; } static void selectBlockMAC(int *macBytes, int *macRandBytes) { - // xgroup(setup) - bool addMAC = boolDefaultNo( - _("Enable block authentication code headers\n" - "on every block in a file? This adds about 12 bytes per block\n" - "to the storage requirements for a file, and significantly affects\n" - "performance but it also means [almost] any modifications or errors\n" - "within a block will be caught and will cause a read error.")); + // xgroup(setup) + bool addMAC = boolDefaultNo( + _("Enable block authentication code headers\n" + "on every block in a file? This adds about 12 bytes per block\n" + "to the storage requirements for a file, and significantly affects\n" + "performance but it also means [almost] any modifications or errors\n" + "within a block will be caught and will cause a read error.")); - if(addMAC) - *macBytes = 8; - else - *macBytes = 0; + if(addMAC) + *macBytes = 8; + else + *macBytes = 0; - // xgroup(setup) - cout << _("Add random bytes to each block header?\n" - "This adds a performance penalty, but ensures that blocks\n" - "have different authentication codes. Note that you can\n" - "have the same benefits by enabling per-file initialization\n" - "vectors, which does not come with as great of performance\n" - "penalty. \n" - "Select a number of bytes, from 0 (no random bytes) to 8: "); + // xgroup(setup) + cout << _("Add random bytes to each block header?\n" + "This adds a performance penalty, but ensures that blocks\n" + "have different authentication codes. Note that you can\n" + "have the same benefits by enabling per-file initialization\n" + "vectors, which does not come with as great of performance\n" + "penalty. \n" + "Select a number of bytes, from 0 (no random bytes) to 8: "); - char answer[10]; - int randSize = 0; - char *res = fgets( answer, sizeof(answer), stdin ); - cout << "\n"; + char answer[10]; + int randSize = 0; + char *res = fgets( answer, sizeof(answer), stdin ); + cout << "\n"; - randSize = (res == 0 ? 0 : atoi( answer )); - if(randSize < 0) - randSize = 0; - if(randSize > 8) - randSize = 8; + randSize = (res == 0 ? 0 : atoi( answer )); + if(randSize < 0) + randSize = 0; + if(randSize > 8) + randSize = 8; - *macRandBytes = randSize; + *macRandBytes = randSize; } static bool boolDefaultYes(const char *prompt) { - cout << prompt << "\n"; - cout << _("The default here is Yes.\n" - "Any response that does not begin with 'n' will mean Yes: "); + cout << prompt << "\n"; + cout << _("The default here is Yes.\n" + "Any response that does not begin with 'n' will mean Yes: "); - char answer[10]; - char *res = fgets( answer, sizeof(answer), stdin ); - cout << "\n"; + char answer[10]; + char *res = fgets( answer, sizeof(answer), stdin ); + cout << "\n"; - if(res != 0 && tolower(answer[0]) == 'n') - return false; - else - return true; + if(res != 0 && tolower(answer[0]) == 'n') + return false; + else + return true; } static bool selectUniqueIV() { - // xgroup(setup) - return boolDefaultYes( - _("Enable per-file initialization vectors?\n" - "This adds about 8 bytes per file to the storage requirements.\n" - "It should not affect performance except possibly with applications\n" - "which rely on block-aligned file io for performance.")); + // xgroup(setup) + return boolDefaultYes( + _("Enable per-file initialization vectors?\n" + "This adds about 8 bytes per file to the storage requirements.\n" + "It should not affect performance except possibly with applications\n" + "which rely on block-aligned file io for performance.")); } static bool selectChainedIV() { - // xgroup(setup) - return boolDefaultYes( - _("Enable filename initialization vector chaining?\n" - "This makes filename encoding dependent on the complete path, \n" - "rather then encoding each path element individually.")); + // xgroup(setup) + return boolDefaultYes( + _("Enable filename initialization vector chaining?\n" + "This makes filename encoding dependent on the complete path, \n" + "rather then encoding each path element individually.")); } static bool selectExternalChainedIV() { - // xgroup(setup) - return boolDefaultNo( - _("Enable filename to IV header chaining?\n" - "This makes file data encoding dependent on the complete file path.\n" - "If a file is renamed, it will not decode sucessfully unless it\n" - "was renamed by encfs with the proper key.\n" - "If this option is enabled, then hard links will not be supported\n" - "in the filesystem.")); + // xgroup(setup) + return boolDefaultNo( + _("Enable filename to IV header chaining?\n" + "This makes file data encoding dependent on the complete file path.\n" + "If a file is renamed, it will not decode sucessfully unless it\n" + "was renamed by encfs with the proper key.\n" + "If this option is enabled, then hard links will not be supported\n" + "in the filesystem.")); } static bool selectZeroBlockPassThrough() { - // xgroup(setup) - return boolDefaultYes( - _("Enable file-hole pass-through?\n" - "This avoids writing encrypted blocks when file holes are created.")); + // xgroup(setup) + return boolDefaultYes( + _("Enable file-hole pass-through?\n" + "This avoids writing encrypted blocks when file holes are created.")); } RootPtr createV6Config( EncFS_Context *ctx, - const shared_ptr &opts ) + const shared_ptr &opts ) { - const std::string rootDir = opts->rootDir; - bool enableIdleTracking = opts->idleTracking; - bool forceDecode = opts->forceDecode; - const std::string passwordProgram = opts->passwordProgram; - bool useStdin = opts->useStdin; - bool reverseEncryption = opts->reverseEncryption; - ConfigMode configMode = opts->configMode; - bool annotate = opts->annotate; - - RootPtr rootInfo; + const std::string rootDir = opts->rootDir; + bool enableIdleTracking = opts->idleTracking; + bool forceDecode = opts->forceDecode; + const std::string passwordProgram = opts->passwordProgram; + bool useStdin = opts->useStdin; + bool reverseEncryption = opts->reverseEncryption; + ConfigMode configMode = opts->configMode; + bool annotate = opts->annotate; - // creating new volume key.. should check that is what the user is - // expecting... + RootPtr rootInfo; + + // creating new volume key.. should check that is what the user is + // expecting... + // xgroup(setup) + cout << _("Creating new encrypted volume.") << endl; + + char answer[10] = {0}; + if(configMode == Config_Prompt) + { // xgroup(setup) - cout << _("Creating new encrypted volume.") << endl; + cout << _("Please choose from one of the following options:\n" + " enter \"x\" for expert configuration mode,\n" + " enter \"p\" for pre-configured paranoia mode,\n" + " anything else, or an empty line will select standard mode.\n" + "?> "); - char answer[10] = {0}; - if(configMode == Config_Prompt) - { - // xgroup(setup) - cout << _("Please choose from one of the following options:\n" - " enter \"x\" for expert configuration mode,\n" - " enter \"p\" for pre-configured paranoia mode,\n" - " anything else, or an empty line will select standard mode.\n" - "?> "); - - if (annotate) - cerr << "$PROMPT$ config_option" << endl; + if (annotate) + cerr << "$PROMPT$ config_option" << endl; - char *res = fgets( answer, sizeof(answer), stdin ); - (void)res; - cout << "\n"; - } + char *res = fgets( answer, sizeof(answer), stdin ); + (void)res; + cout << "\n"; + } - int keySize = 0; - int blockSize = 0; - Cipher::CipherAlgorithm alg; - Interface nameIOIface; - int blockMACBytes = 0; - int blockMACRandBytes = 0; - bool uniqueIV = false; - bool chainedIV = false; - bool externalIV = false; - bool allowHoles = true; - long desiredKDFDuration = NormalKDFDuration; - + int keySize = 0; + int blockSize = 0; + Cipher::CipherAlgorithm alg; + Interface nameIOIface; + int blockMACBytes = 0; + int blockMACRandBytes = 0; + bool uniqueIV = false; + bool chainedIV = false; + bool externalIV = false; + bool allowHoles = true; + long desiredKDFDuration = NormalKDFDuration; + + if (reverseEncryption) + { + uniqueIV = false; + chainedIV = false; + externalIV = false; + blockMACBytes = 0; + blockMACRandBytes = 0; + } + + if(configMode == Config_Paranoia || answer[0] == 'p') + { if (reverseEncryption) { - uniqueIV = false; - chainedIV = false; - externalIV = false; - blockMACBytes = 0; - blockMACRandBytes = 0; + rError(_("Paranoia configuration not supported for --reverse")); + return rootInfo; } - if(configMode == Config_Paranoia || answer[0] == 'p') + // xgroup(setup) + cout << _("Paranoia configuration selected.") << "\n"; + // look for AES with 256 bit key.. + // Use block filename encryption mode. + // Enable per-block HMAC headers at substantial performance penalty.. + // Enable per-file initialization vector headers. + // Enable filename initialization vector chaning + keySize = 256; + blockSize = DefaultBlockSize; + alg = findCipherAlgorithm("AES", keySize); + nameIOIface = BlockNameIO::CurrentInterface(); + blockMACBytes = 8; + blockMACRandBytes = 0; // using uniqueIV, so this isn't necessary + uniqueIV = true; + chainedIV = true; + externalIV = true; + desiredKDFDuration = ParanoiaKDFDuration; + } else if(configMode == Config_Standard || answer[0] != 'x') + { + // xgroup(setup) + cout << _("Standard configuration selected.") << "\n"; + // AES w/ 192 bit key, block name encoding, per-file initialization + // vectors are all standard. + keySize = 192; + blockSize = DefaultBlockSize; + alg = findCipherAlgorithm("AES", keySize); + blockMACBytes = 0; + externalIV = false; + nameIOIface = BlockNameIO::CurrentInterface(); + + if (reverseEncryption) { - if (reverseEncryption) - { - rError(_("Paranoia configuration not supported for --reverse")); - return rootInfo; - } - - // xgroup(setup) - cout << _("Paranoia configuration selected.") << "\n"; - // look for AES with 256 bit key.. - // Use block filename encryption mode. - // Enable per-block HMAC headers at substantial performance penalty.. - // Enable per-file initialization vector headers. - // Enable filename initialization vector chaning - keySize = 256; - blockSize = DefaultBlockSize; - alg = findCipherAlgorithm("AES", keySize); - nameIOIface = BlockNameIO::CurrentInterface(); - blockMACBytes = 8; - blockMACRandBytes = 0; // using uniqueIV, so this isn't necessary - uniqueIV = true; - chainedIV = true; - externalIV = true; - desiredKDFDuration = ParanoiaKDFDuration; - } else if(configMode == Config_Standard || answer[0] != 'x') - { - // xgroup(setup) - cout << _("Standard configuration selected.") << "\n"; - // AES w/ 192 bit key, block name encoding, per-file initialization - // vectors are all standard. - keySize = 192; - blockSize = DefaultBlockSize; - alg = findCipherAlgorithm("AES", keySize); - blockMACBytes = 0; - externalIV = false; - nameIOIface = BlockNameIO::CurrentInterface(); - - if (reverseEncryption) - { - cout << _("--reverse specified, not using unique/chained IV") - << "\n"; - } else - { - uniqueIV = true; - chainedIV = true; - } - } - - if(answer[0] == 'x' || alg.name.empty()) - { - if(answer[0] != 'x') - { - // xgroup(setup) - cout << _("Sorry, unable to locate cipher for predefined " - "configuration...\n" - "Falling through to Manual configuration mode."); - } else - { - // xgroup(setup) - cout << _("Manual configuration mode selected."); - } - cout << endl; - - // query user for settings.. - alg = selectCipherAlgorithm(); - keySize = selectKeySize( alg ); - blockSize = selectBlockSize( alg ); - nameIOIface = selectNameCoding(); - if (reverseEncryption) - { - cout << _("--reverse specified, not using unique/chained IV") << "\n"; - } else - { - chainedIV = selectChainedIV(); - uniqueIV = selectUniqueIV(); - if(chainedIV && uniqueIV) - externalIV = selectExternalChainedIV(); - else - { - // xgroup(setup) - cout << _("External chained IV disabled, as both 'IV chaining'\n" - "and 'unique IV' features are required for this option.") - << "\n"; - externalIV = false; - } - selectBlockMAC(&blockMACBytes, &blockMACRandBytes); - allowHoles = selectZeroBlockPassThrough(); - } - } - - shared_ptr cipher = Cipher::New( alg.name, keySize ); - if(!cipher) - { - rError(_("Unable to instanciate cipher %s, key size %i, block size %i"), - alg.name.c_str(), keySize, blockSize); - return rootInfo; + cout << _("--reverse specified, not using unique/chained IV") + << "\n"; } else { - rDebug("Using cipher %s, key size %i, block size %i", - alg.name.c_str(), keySize, blockSize); + uniqueIV = true; + chainedIV = true; } - - shared_ptr config( new EncFSConfig ); + } - config->cfgType = Config_V6; - config->cipherIface = cipher->interface(); - config->keySize = keySize; - config->blockSize = blockSize; - config->nameIface = nameIOIface; - config->creator = "EncFS " VERSION; - config->subVersion = V6SubVersion; - config->blockMACBytes = blockMACBytes; - config->blockMACRandBytes = blockMACRandBytes; - config->uniqueIV = uniqueIV; - config->chainedNameIV = chainedIV; - config->externalIVChaining = externalIV; - config->allowHoles = allowHoles; - - config->salt.clear(); - config->kdfIterations = 0; // filled in by keying function - config->desiredKDFDuration = desiredKDFDuration; - - cout << "\n"; - // xgroup(setup) - cout << _("Configuration finished. The filesystem to be created has\n" - "the following properties:") << endl; - showFSInfo( config ); - - if( config->externalIVChaining ) + if(answer[0] == 'x' || alg.name.empty()) + { + if(answer[0] != 'x') { - cout << - _("-------------------------- WARNING --------------------------\n") - << - _("The external initialization-vector chaining option has been\n" - "enabled. This option disables the use of hard links on the\n" - "filesystem. Without hard links, some programs may not work.\n" - "The programs 'mutt' and 'procmail' are known to fail. For\n" - "more information, please see the encfs mailing list.\n" - "If you would like to choose another configuration setting,\n" - "please press CTRL-C now to abort and start over.") << endl; - cout << endl; - } - - // xgroup(setup) - cout << _("Now you will need to enter a password for your filesystem.\n" - "You will need to remember this password, as there is absolutely\n" - "no recovery mechanism. However, the password can be changed\n" - "later using encfsctl.\n\n"); - - int encodedKeySize = cipher->encodedKeySize(); - unsigned char *encodedKey = new unsigned char[ encodedKeySize ]; - - CipherKey volumeKey = cipher->newRandomKey(); - - // get user key and use it to encode volume key - CipherKey userKey; - rDebug( "useStdin: %i", useStdin ); - if(useStdin) + // xgroup(setup) + cout << _("Sorry, unable to locate cipher for predefined " + "configuration...\n" + "Falling through to Manual configuration mode."); + } else { - if (annotate) - cerr << "$PROMPT$ new_passwd" << endl; - userKey = config->getUserKey( useStdin ); + // xgroup(setup) + cout << _("Manual configuration mode selected."); } - else if(!passwordProgram.empty()) - userKey = config->getUserKey( passwordProgram, rootDir ); + cout << endl; + + // query user for settings.. + alg = selectCipherAlgorithm(); + keySize = selectKeySize( alg ); + blockSize = selectBlockSize( alg ); + nameIOIface = selectNameCoding(); + if (reverseEncryption) + { + cout << _("--reverse specified, not using unique/chained IV") << "\n"; + } else + { + chainedIV = selectChainedIV(); + uniqueIV = selectUniqueIV(); + if(chainedIV && uniqueIV) + externalIV = selectExternalChainedIV(); + else + { + // xgroup(setup) + cout << _("External chained IV disabled, as both 'IV chaining'\n" + "and 'unique IV' features are required for this option.") + << "\n"; + externalIV = false; + } + selectBlockMAC(&blockMACBytes, &blockMACRandBytes); + allowHoles = selectZeroBlockPassThrough(); + } + } + + shared_ptr cipher = Cipher::New( alg.name, keySize ); + if(!cipher) + { + rError(_("Unable to instanciate cipher %s, key size %i, block size %i"), + alg.name.c_str(), keySize, blockSize); + return rootInfo; + } else + { + rDebug("Using cipher %s, key size %i, block size %i", + alg.name.c_str(), keySize, blockSize); + } + + shared_ptr config( new EncFSConfig ); + + config->cfgType = Config_V6; + config->cipherIface = cipher->interface(); + config->keySize = keySize; + config->blockSize = blockSize; + config->nameIface = nameIOIface; + config->creator = "EncFS " VERSION; + config->subVersion = V6SubVersion; + config->blockMACBytes = blockMACBytes; + config->blockMACRandBytes = blockMACRandBytes; + config->uniqueIV = uniqueIV; + config->chainedNameIV = chainedIV; + config->externalIVChaining = externalIV; + config->allowHoles = allowHoles; + + config->salt.clear(); + config->kdfIterations = 0; // filled in by keying function + config->desiredKDFDuration = desiredKDFDuration; + + cout << "\n"; + // xgroup(setup) + cout << _("Configuration finished. The filesystem to be created has\n" + "the following properties:") << endl; + showFSInfo( config ); + + if( config->externalIVChaining ) + { + cout << + _("-------------------------- WARNING --------------------------\n") + << + _("The external initialization-vector chaining option has been\n" + "enabled. This option disables the use of hard links on the\n" + "filesystem. Without hard links, some programs may not work.\n" + "The programs 'mutt' and 'procmail' are known to fail. For\n" + "more information, please see the encfs mailing list.\n" + "If you would like to choose another configuration setting,\n" + "please press CTRL-C now to abort and start over.") << endl; + cout << endl; + } + + // xgroup(setup) + cout << _("Now you will need to enter a password for your filesystem.\n" + "You will need to remember this password, as there is absolutely\n" + "no recovery mechanism. However, the password can be changed\n" + "later using encfsctl.\n\n"); + + int encodedKeySize = cipher->encodedKeySize(); + unsigned char *encodedKey = new unsigned char[ encodedKeySize ]; + + CipherKey volumeKey = cipher->newRandomKey(); + + // get user key and use it to encode volume key + CipherKey userKey; + rDebug( "useStdin: %i", useStdin ); + if(useStdin) + { + if (annotate) + cerr << "$PROMPT$ new_passwd" << endl; + userKey = config->getUserKey( useStdin ); + } + else if(!passwordProgram.empty()) + userKey = config->getUserKey( passwordProgram, rootDir ); + else + userKey = config->getNewUserKey(); + + cipher->writeKey( volumeKey, encodedKey, userKey ); + userKey.reset(); + + config->assignKeyData(encodedKey, encodedKeySize); + delete[] encodedKey; + + if(!volumeKey) + { + rWarning(_("Failure generating new volume key! " + "Please report this error.")); + return rootInfo; + } + + if(!saveConfig( Config_V6, rootDir, config )) + return rootInfo; + + // fill in config struct + shared_ptr nameCoder = NameIO::New( config->nameIface, + cipher, volumeKey ); + if(!nameCoder) + { + rWarning(_("Name coding interface not supported")); + cout << _("The filename encoding interface requested is not available") + << endl; + return rootInfo; + } + + nameCoder->setChainedNameIV( config->chainedNameIV ); + nameCoder->setReverseEncryption( reverseEncryption ); + + FSConfigPtr fsConfig (new FSConfig); + fsConfig->cipher = cipher; + fsConfig->key = volumeKey; + fsConfig->nameCoding = nameCoder; + fsConfig->config = config; + fsConfig->forceDecode = forceDecode; + fsConfig->reverseEncryption = reverseEncryption; + fsConfig->idleTracking = enableIdleTracking; + fsConfig->opts = opts; + + rootInfo = RootPtr( new EncFS_Root ); + rootInfo->cipher = cipher; + rootInfo->volumeKey = volumeKey; + rootInfo->root = shared_ptr( + new DirNode( ctx, rootDir, fsConfig )); + + return rootInfo; +} + +void showFSInfo( const boost::shared_ptr &config ) +{ + shared_ptr cipher = Cipher::New( config->cipherIface, -1 ); + { + cout << autosprintf( + // xgroup(diag) + _("Filesystem cipher: \"%s\", version %i:%i:%i"), + config->cipherIface.name().c_str(), config->cipherIface.current(), + config->cipherIface.revision(), config->cipherIface.age()); + // check if we support this interface.. + if(!cipher) + cout << _(" (NOT supported)\n"); else - userKey = config->getNewUserKey(); + { + // if we're using a newer interface, show the version number + if( config->cipherIface != cipher->interface() ) + { + Interface iface = cipher->interface(); + // xgroup(diag) + cout << autosprintf(_(" (using %i:%i:%i)\n"), + iface.current(), iface.revision(), iface.age()); + } else + cout << "\n"; + } + } + { + // xgroup(diag) + cout << autosprintf(_("Filename encoding: \"%s\", version %i:%i:%i"), + config->nameIface.name().c_str(), config->nameIface.current(), + config->nameIface.revision(), config->nameIface.age()); - cipher->writeKey( volumeKey, encodedKey, userKey ); + // check if we support the filename encoding interface.. + shared_ptr nameCoder = NameIO::New( config->nameIface, + cipher, CipherKey() ); + if(!nameCoder) + { + // xgroup(diag) + cout << _(" (NOT supported)\n"); + } else + { + // if we're using a newer interface, show the version number + if( config->nameIface != nameCoder->interface() ) + { + Interface iface = nameCoder->interface(); + cout << autosprintf(_(" (using %i:%i:%i)\n"), + iface.current(), iface.revision(), iface.age()); + } else + cout << "\n"; + } + } + { + cout << autosprintf(_("Key Size: %i bits"), config->keySize); + cipher = config->getCipher(); + if(!cipher) + { + // xgroup(diag) + cout << _(" (NOT supported)\n"); + } else + cout << "\n"; + } + if(config->kdfIterations > 0 && config->salt.size() > 0) + { + cout << autosprintf(_("Using PBKDF2, with %i iterations"), + config->kdfIterations) << "\n"; + cout << autosprintf(_("Salt Size: %i bits"), + 8*(int)config->salt.size()) << "\n"; + } + if(config->blockMACBytes || config->blockMACRandBytes) + { + if(config->subVersion < 20040813) + { + cout << autosprintf( + // xgroup(diag) + _("Block Size: %i bytes + %i byte MAC header"), + config->blockSize, + config->blockMACBytes + config->blockMACRandBytes) << endl; + } else + { + // new version stores the header as part of that block size.. + cout << autosprintf( + // xgroup(diag) + _("Block Size: %i bytes, including %i byte MAC header"), + config->blockSize, + config->blockMACBytes + config->blockMACRandBytes) << endl; + } + } else + { + // xgroup(diag) + cout << autosprintf(_("Block Size: %i bytes"), config->blockSize); + cout << "\n"; + } + + if(config->uniqueIV) + { + // xgroup(diag) + cout << _("Each file contains 8 byte header with unique IV data.\n"); + } + if(config->chainedNameIV) + { + // xgroup(diag) + cout << _("Filenames encoded using IV chaining mode.\n"); + } + if(config->externalIVChaining) + { + // xgroup(diag) + cout << _("File data IV is chained to filename IV.\n"); + } + if(config->allowHoles) + { + // xgroup(diag) + cout << _("File holes passed through to ciphertext.\n"); + } + cout << "\n"; +} + +shared_ptr EncFSConfig::getCipher() const +{ + return Cipher::New( cipherIface, keySize ); +} + +void EncFSConfig::assignKeyData(const std::string &in) +{ + keyData.assign(in.data(), in.data()+in.length()); +} + +void EncFSConfig::assignKeyData(unsigned char *data, int len) +{ + keyData.assign(data, data+len); +} + +void EncFSConfig::assignSaltData(unsigned char *data, int len) +{ + salt.assign(data, data+len); +} + +unsigned char *EncFSConfig::getKeyData() const +{ + return const_cast(&keyData.front()); +} + +unsigned char *EncFSConfig::getSaltData() const +{ + return const_cast(&salt.front()); +} + +CipherKey EncFSConfig::makeKey(const char *password, int passwdLen) +{ + CipherKey userKey; + shared_ptr cipher = getCipher(); + + // if no salt is set and we're creating a new password for a new + // FS type, then initialize salt.. + if(salt.size() == 0 && kdfIterations == 0 && cfgType >= Config_V6) + { + // upgrade to using salt + salt.resize(20); + } + + if(salt.size() > 0) + { + // if iterations isn't known, then we're creating a new key, so + // randomize the salt.. + if(kdfIterations == 0 && !cipher->randomize( + getSaltData(), salt.size(), true)) + { + cout << _("Error creating salt\n"); + return userKey; + } + + userKey = cipher->newKey( password, passwdLen, + kdfIterations, desiredKDFDuration, + getSaltData(), salt.size()); + } else + { + userKey = cipher->newKey( password, passwdLen ); + } + + return userKey; +} + +CipherKey EncFSConfig::getUserKey(bool useStdin) +{ + char passBuf[MaxPassBuf]; + char *res; + + if( useStdin ) + { + res = fgets( passBuf, sizeof(passBuf), stdin ); + // Kill the trailing newline. + if(passBuf[ strlen(passBuf)-1 ] == '\n') + passBuf[ strlen(passBuf)-1 ] = '\0'; + } else + { + // xgroup(common) + res = readpassphrase( _("EncFS Password: "), + passBuf, sizeof(passBuf), RPP_ECHO_OFF ); + } + + CipherKey userKey; + if(!res) + cerr << _("Zero length password not allowed\n"); + else + userKey = makeKey(passBuf, strlen(passBuf)); + + memset( passBuf, 0, sizeof(passBuf) ); + + return userKey; +} + +std::string readPassword( int FD ) +{ + char buffer[1024]; + string result; + + while(1) + { + ssize_t rdSize = recv(FD, buffer, sizeof(buffer), 0); + + if(rdSize > 0) + { + result.append( buffer, rdSize ); + memset(buffer, 0, sizeof(buffer)); + } else + break; + } + + // chop off trailing "\n" if present.. + // This is done so that we can use standard programs like ssh-askpass + // without modification, as it returns trailing newline.. + if(!result.empty() && result[ result.length()-1 ] == '\n' ) + result.resize( result.length() -1 ); + + return result; +} + +CipherKey EncFSConfig::getUserKey( const std::string &passProg, + const std::string &rootDir ) +{ + // have a child process run the command and get the result back to us. + int fds[2], pid; + int res; + CipherKey result; + + res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); + if(res == -1) + { + perror(_("Internal error: socketpair() failed")); + return result; + } + rDebug("getUserKey: fds = %i, %i", fds[0], fds[1]); + + pid = fork(); + if(pid == -1) + { + perror(_("Internal error: fork() failed")); + close(fds[0]); + close(fds[1]); + return result; + } + + if(pid == 0) + { + const char *argv[4]; + argv[0] = "/bin/sh"; + argv[1] = "-c"; + argv[2] = passProg.c_str(); + argv[3] = 0; + + // child process.. run the command and send output to fds[0] + close(fds[1]); // we don't use the other half.. + + // make a copy of stdout and stderr descriptors, and set an environment + // variable telling where to find them, in case a child wants it.. + int stdOutCopy = dup( STDOUT_FILENO ); + int stdErrCopy = dup( STDERR_FILENO ); + // replace STDOUT with our socket, which we'll used to receive the + // password.. + dup2( fds[0], STDOUT_FILENO ); + + // ensure that STDOUT_FILENO and stdout/stderr are not closed on exec.. + fcntl(STDOUT_FILENO, F_SETFD, 0); // don't close on exec.. + fcntl(stdOutCopy, F_SETFD, 0); + fcntl(stdErrCopy, F_SETFD, 0); + + char tmpBuf[8]; + + setenv(ENCFS_ENV_ROOTDIR, rootDir.c_str(), 1); + + snprintf(tmpBuf, sizeof(tmpBuf)-1, "%i", stdOutCopy); + setenv(ENCFS_ENV_STDOUT, tmpBuf, 1); + + snprintf(tmpBuf, sizeof(tmpBuf)-1, "%i", stdErrCopy); + setenv(ENCFS_ENV_STDERR, tmpBuf, 1); + + execvp( argv[0], (char * const *)argv ); // returns only on error.. + + perror(_("Internal error: failed to exec program")); + exit(1); + } + + close(fds[0]); + string password = readPassword(fds[1]); + close(fds[1]); + + waitpid(pid, NULL, 0); + + // convert to key.. + result = makeKey(password.c_str(), password.length()); + + // clear buffer.. + password.assign( password.length(), '\0' ); + + return result; +} + +CipherKey EncFSConfig::getNewUserKey() +{ + CipherKey userKey; + char passBuf[MaxPassBuf]; + char passBuf2[MaxPassBuf]; + + do + { + // xgroup(common) + char *res1 = readpassphrase(_("New Encfs Password: "), passBuf, + sizeof(passBuf)-1, RPP_ECHO_OFF); + // xgroup(common) + char *res2 = readpassphrase(_("Verify Encfs Password: "), passBuf2, + sizeof(passBuf2)-1, RPP_ECHO_OFF); + + if(res1 && res2 && !strcmp(passBuf, passBuf2)) + { + userKey = makeKey(passBuf, strlen(passBuf)); + } else + { + // xgroup(common) -- probably not common, but group with the others + cerr << _("Passwords did not match, please try again\n"); + } + + memset( passBuf, 0, sizeof(passBuf) ); + memset( passBuf2, 0, sizeof(passBuf2) ); + } while( !userKey ); + + return userKey; +} + +RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) +{ + RootPtr rootInfo; + boost::shared_ptr config(new EncFSConfig); + + if(readConfig( opts->rootDir, config ) != Config_None) + { + if(opts->reverseEncryption) + { + if (config->blockMACBytes != 0 || config->blockMACRandBytes != 0 + || config->uniqueIV || config->externalIVChaining + || config->chainedNameIV ) + { + cout << _("The configuration loaded is not compatible with --reverse\n"); + return rootInfo; + } + } + + // first, instanciate the cipher. + shared_ptr cipher = config->getCipher(); + if(!cipher) + { + rError(_("Unable to find cipher %s, version %i:%i:%i"), + config->cipherIface.name().c_str(), + config->cipherIface.current(), + config->cipherIface.revision(), + config->cipherIface.age()); + // xgroup(diag) + cout << _("The requested cipher interface is not available\n"); + return rootInfo; + } + + // get user key + CipherKey userKey; + + if(opts->passwordProgram.empty()) + { + rDebug( "useStdin: %i", opts->useStdin ); + if (opts->annotate) + cerr << "$PROMPT$ passwd" << endl; + userKey = config->getUserKey( opts->useStdin ); + } else + userKey = config->getUserKey( opts->passwordProgram, opts->rootDir ); + + if(!userKey) + return rootInfo; + + rDebug("cipher key size = %i", cipher->encodedKeySize()); + // decode volume key.. + CipherKey volumeKey = cipher->readKey( + config->getKeyData(), userKey, opts->checkKey); userKey.reset(); - config->assignKeyData(encodedKey, encodedKeySize); - delete[] encodedKey; - if(!volumeKey) { - rWarning(_("Failure generating new volume key! " - "Please report this error.")); - return rootInfo; + // xgroup(diag) + cout << _("Error decoding volume key, password incorrect\n"); + return rootInfo; } - if(!saveConfig( Config_V6, rootDir, config )) - return rootInfo; - - // fill in config struct - shared_ptr nameCoder = NameIO::New( config->nameIface, - cipher, volumeKey ); + shared_ptr nameCoder = NameIO::New( config->nameIface, + cipher, volumeKey ); if(!nameCoder) { - rWarning(_("Name coding interface not supported")); - cout << _("The filename encoding interface requested is not available") - << endl; - return rootInfo; + rError(_("Unable to find nameio interface %s, version %i:%i:%i"), + config->nameIface.name().c_str(), + config->nameIface.current(), + config->nameIface.revision(), + config->nameIface.age()); + // xgroup(diag) + cout << _("The requested filename coding interface is " + "not available\n"); + return rootInfo; } - - nameCoder->setChainedNameIV( config->chainedNameIV ); - nameCoder->setReverseEncryption( reverseEncryption ); - FSConfigPtr fsConfig (new FSConfig); + nameCoder->setChainedNameIV( config->chainedNameIV ); + nameCoder->setReverseEncryption( opts->reverseEncryption ); + + FSConfigPtr fsConfig( new FSConfig ); fsConfig->cipher = cipher; fsConfig->key = volumeKey; fsConfig->nameCoding = nameCoder; fsConfig->config = config; - fsConfig->forceDecode = forceDecode; - fsConfig->reverseEncryption = reverseEncryption; - fsConfig->idleTracking = enableIdleTracking; + fsConfig->forceDecode = opts->forceDecode; + fsConfig->reverseEncryption = opts->reverseEncryption; fsConfig->opts = opts; rootInfo = RootPtr( new EncFS_Root ); rootInfo->cipher = cipher; rootInfo->volumeKey = volumeKey; rootInfo->root = shared_ptr( - new DirNode( ctx, rootDir, fsConfig )); - - return rootInfo; -} - -void showFSInfo( const boost::shared_ptr &config ) -{ - shared_ptr cipher = Cipher::New( config->cipherIface, -1 ); + new DirNode( ctx, opts->rootDir, fsConfig )); + } else + { + if(opts->createIfNotFound) { - cout << autosprintf( - // xgroup(diag) - _("Filesystem cipher: \"%s\", version %i:%i:%i"), - config->cipherIface.name().c_str(), config->cipherIface.current(), - config->cipherIface.revision(), config->cipherIface.age()); - // check if we support this interface.. - if(!cipher) - cout << _(" (NOT supported)\n"); - else - { - // if we're using a newer interface, show the version number - if( config->cipherIface != cipher->interface() ) - { - Interface iface = cipher->interface(); - // xgroup(diag) - cout << autosprintf(_(" (using %i:%i:%i)\n"), - iface.current(), iface.revision(), iface.age()); - } else - cout << "\n"; - } - } - { - // xgroup(diag) - cout << autosprintf(_("Filename encoding: \"%s\", version %i:%i:%i"), - config->nameIface.name().c_str(), config->nameIface.current(), - config->nameIface.revision(), config->nameIface.age()); - - // check if we support the filename encoding interface.. - shared_ptr nameCoder = NameIO::New( config->nameIface, - cipher, CipherKey() ); - if(!nameCoder) - { - // xgroup(diag) - cout << _(" (NOT supported)\n"); - } else - { - // if we're using a newer interface, show the version number - if( config->nameIface != nameCoder->interface() ) - { - Interface iface = nameCoder->interface(); - cout << autosprintf(_(" (using %i:%i:%i)\n"), - iface.current(), iface.revision(), iface.age()); - } else - cout << "\n"; - } - } - { - cout << autosprintf(_("Key Size: %i bits"), config->keySize); - cipher = config->getCipher(); - if(!cipher) - { - // xgroup(diag) - cout << _(" (NOT supported)\n"); - } else - cout << "\n"; - } - if(config->kdfIterations > 0 && config->salt.size() > 0) - { - cout << autosprintf(_("Using PBKDF2, with %i iterations"), - config->kdfIterations) << "\n"; - cout << autosprintf(_("Salt Size: %i bits"), - 8*(int)config->salt.size()) << "\n"; - } - if(config->blockMACBytes || config->blockMACRandBytes) - { - if(config->subVersion < 20040813) - { - cout << autosprintf( - // xgroup(diag) - _("Block Size: %i bytes + %i byte MAC header"), - config->blockSize, - config->blockMACBytes + config->blockMACRandBytes) << endl; - } else - { - // new version stores the header as part of that block size.. - cout << autosprintf( - // xgroup(diag) - _("Block Size: %i bytes, including %i byte MAC header"), - config->blockSize, - config->blockMACBytes + config->blockMACRandBytes) << endl; - } - } else - { - // xgroup(diag) - cout << autosprintf(_("Block Size: %i bytes"), config->blockSize); - cout << "\n"; + // creating a new encrypted filesystem + rootInfo = createV6Config( ctx, opts ); } + } - if(config->uniqueIV) - { - // xgroup(diag) - cout << _("Each file contains 8 byte header with unique IV data.\n"); - } - if(config->chainedNameIV) - { - // xgroup(diag) - cout << _("Filenames encoded using IV chaining mode.\n"); - } - if(config->externalIVChaining) - { - // xgroup(diag) - cout << _("File data IV is chained to filename IV.\n"); - } - if(config->allowHoles) - { - // xgroup(diag) - cout << _("File holes passed through to ciphertext.\n"); - } - cout << "\n"; -} - -shared_ptr EncFSConfig::getCipher() const -{ - return Cipher::New( cipherIface, keySize ); -} - -void EncFSConfig::assignKeyData(const std::string &in) -{ - keyData.assign(in.data(), in.data()+in.length()); -} - -void EncFSConfig::assignKeyData(unsigned char *data, int len) -{ - keyData.assign(data, data+len); -} - -void EncFSConfig::assignSaltData(unsigned char *data, int len) -{ - salt.assign(data, data+len); -} - -unsigned char *EncFSConfig::getKeyData() const -{ - return const_cast(&keyData.front()); -} - -unsigned char *EncFSConfig::getSaltData() const -{ - return const_cast(&salt.front()); -} - -CipherKey EncFSConfig::makeKey(const char *password, int passwdLen) -{ - CipherKey userKey; - shared_ptr cipher = getCipher(); - - // if no salt is set and we're creating a new password for a new - // FS type, then initialize salt.. - if(salt.size() == 0 && kdfIterations == 0 && cfgType >= Config_V6) - { - // upgrade to using salt - salt.resize(20); - } - - if(salt.size() > 0) - { - // if iterations isn't known, then we're creating a new key, so - // randomize the salt.. - if(kdfIterations == 0 && !cipher->randomize( - getSaltData(), salt.size(), true)) - { - cout << _("Error creating salt\n"); - return userKey; - } - - userKey = cipher->newKey( password, passwdLen, - kdfIterations, desiredKDFDuration, - getSaltData(), salt.size()); - } else - { - userKey = cipher->newKey( password, passwdLen ); - } - - return userKey; -} - -CipherKey EncFSConfig::getUserKey(bool useStdin) -{ - char passBuf[MaxPassBuf]; - char *res; - - if( useStdin ) - { - res = fgets( passBuf, sizeof(passBuf), stdin ); - // Kill the trailing newline. - if(passBuf[ strlen(passBuf)-1 ] == '\n') - passBuf[ strlen(passBuf)-1 ] = '\0'; - } else - { - // xgroup(common) - res = readpassphrase( _("EncFS Password: "), - passBuf, sizeof(passBuf), RPP_ECHO_OFF ); - } - - CipherKey userKey; - if(!res) - cerr << _("Zero length password not allowed\n"); - else - userKey = makeKey(passBuf, strlen(passBuf)); - - memset( passBuf, 0, sizeof(passBuf) ); - - return userKey; -} - -std::string readPassword( int FD ) -{ - char buffer[1024]; - string result; - - while(1) - { - ssize_t rdSize = recv(FD, buffer, sizeof(buffer), 0); - - if(rdSize > 0) - { - result.append( buffer, rdSize ); - memset(buffer, 0, sizeof(buffer)); - } else - break; - } - - // chop off trailing "\n" if present.. - // This is done so that we can use standard programs like ssh-askpass - // without modification, as it returns trailing newline.. - if(!result.empty() && result[ result.length()-1 ] == '\n' ) - result.resize( result.length() -1 ); - - return result; -} - -CipherKey EncFSConfig::getUserKey( const std::string &passProg, - const std::string &rootDir ) -{ - // have a child process run the command and get the result back to us. - int fds[2], pid; - int res; - CipherKey result; - - res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); - if(res == -1) - { - perror(_("Internal error: socketpair() failed")); - return result; - } - rDebug("getUserKey: fds = %i, %i", fds[0], fds[1]); - - pid = fork(); - if(pid == -1) - { - perror(_("Internal error: fork() failed")); - close(fds[0]); - close(fds[1]); - return result; - } - - if(pid == 0) - { - const char *argv[4]; - argv[0] = "/bin/sh"; - argv[1] = "-c"; - argv[2] = passProg.c_str(); - argv[3] = 0; - - // child process.. run the command and send output to fds[0] - close(fds[1]); // we don't use the other half.. - - // make a copy of stdout and stderr descriptors, and set an environment - // variable telling where to find them, in case a child wants it.. - int stdOutCopy = dup( STDOUT_FILENO ); - int stdErrCopy = dup( STDERR_FILENO ); - // replace STDOUT with our socket, which we'll used to receive the - // password.. - dup2( fds[0], STDOUT_FILENO ); - - // ensure that STDOUT_FILENO and stdout/stderr are not closed on exec.. - fcntl(STDOUT_FILENO, F_SETFD, 0); // don't close on exec.. - fcntl(stdOutCopy, F_SETFD, 0); - fcntl(stdErrCopy, F_SETFD, 0); - - char tmpBuf[8]; - - setenv(ENCFS_ENV_ROOTDIR, rootDir.c_str(), 1); - - snprintf(tmpBuf, sizeof(tmpBuf)-1, "%i", stdOutCopy); - setenv(ENCFS_ENV_STDOUT, tmpBuf, 1); - - snprintf(tmpBuf, sizeof(tmpBuf)-1, "%i", stdErrCopy); - setenv(ENCFS_ENV_STDERR, tmpBuf, 1); - - execvp( argv[0], (char * const *)argv ); // returns only on error.. - - perror(_("Internal error: failed to exec program")); - exit(1); - } - - close(fds[0]); - string password = readPassword(fds[1]); - close(fds[1]); - - waitpid(pid, NULL, 0); - - // convert to key.. - result = makeKey(password.c_str(), password.length()); - - // clear buffer.. - password.assign( password.length(), '\0' ); - - return result; -} - -CipherKey EncFSConfig::getNewUserKey() -{ - CipherKey userKey; - char passBuf[MaxPassBuf]; - char passBuf2[MaxPassBuf]; - - do - { - // xgroup(common) - char *res1 = readpassphrase(_("New Encfs Password: "), passBuf, - sizeof(passBuf)-1, RPP_ECHO_OFF); - // xgroup(common) - char *res2 = readpassphrase(_("Verify Encfs Password: "), passBuf2, - sizeof(passBuf2)-1, RPP_ECHO_OFF); - - if(res1 && res2 && !strcmp(passBuf, passBuf2)) - { - userKey = makeKey(passBuf, strlen(passBuf)); - } else - { - // xgroup(common) -- probably not common, but group with the others - cerr << _("Passwords did not match, please try again\n"); - } - - memset( passBuf, 0, sizeof(passBuf) ); - memset( passBuf2, 0, sizeof(passBuf2) ); - } while( !userKey ); - - return userKey; -} - -RootPtr initFS( EncFS_Context *ctx, const shared_ptr &opts ) -{ - RootPtr rootInfo; - boost::shared_ptr config(new EncFSConfig); - - if(readConfig( opts->rootDir, config ) != Config_None) - { - if(opts->reverseEncryption) - { - if (config->blockMACBytes != 0 || config->blockMACRandBytes != 0 - || config->uniqueIV || config->externalIVChaining - || config->chainedNameIV ) - { - cout << _("The configuration loaded is not compatible with --reverse\n"); - return rootInfo; - } - } - - // first, instanciate the cipher. - shared_ptr cipher = config->getCipher(); - if(!cipher) - { - rError(_("Unable to find cipher %s, version %i:%i:%i"), - config->cipherIface.name().c_str(), - config->cipherIface.current(), - config->cipherIface.revision(), - config->cipherIface.age()); - // xgroup(diag) - cout << _("The requested cipher interface is not available\n"); - return rootInfo; - } - - // get user key - CipherKey userKey; - - if(opts->passwordProgram.empty()) - { - rDebug( "useStdin: %i", opts->useStdin ); - if (opts->annotate) - cerr << "$PROMPT$ passwd" << endl; - userKey = config->getUserKey( opts->useStdin ); - } else - userKey = config->getUserKey( opts->passwordProgram, opts->rootDir ); - - if(!userKey) - return rootInfo; - - rDebug("cipher key size = %i", cipher->encodedKeySize()); - // decode volume key.. - CipherKey volumeKey = cipher->readKey( - config->getKeyData(), userKey, opts->checkKey); - userKey.reset(); - - if(!volumeKey) - { - // xgroup(diag) - cout << _("Error decoding volume key, password incorrect\n"); - return rootInfo; - } - - shared_ptr nameCoder = NameIO::New( config->nameIface, - cipher, volumeKey ); - if(!nameCoder) - { - rError(_("Unable to find nameio interface %s, version %i:%i:%i"), - config->nameIface.name().c_str(), - config->nameIface.current(), - config->nameIface.revision(), - config->nameIface.age()); - // xgroup(diag) - cout << _("The requested filename coding interface is " - "not available\n"); - return rootInfo; - } - - nameCoder->setChainedNameIV( config->chainedNameIV ); - nameCoder->setReverseEncryption( opts->reverseEncryption ); - - FSConfigPtr fsConfig( new FSConfig ); - fsConfig->cipher = cipher; - fsConfig->key = volumeKey; - fsConfig->nameCoding = nameCoder; - fsConfig->config = config; - fsConfig->forceDecode = opts->forceDecode; - fsConfig->reverseEncryption = opts->reverseEncryption; - fsConfig->opts = opts; - - rootInfo = RootPtr( new EncFS_Root ); - rootInfo->cipher = cipher; - rootInfo->volumeKey = volumeKey; - rootInfo->root = shared_ptr( - new DirNode( ctx, opts->rootDir, fsConfig )); - } else - { - if(opts->createIfNotFound) - { - // creating a new encrypted filesystem - rootInfo = createV6Config( ctx, opts ); - } - } - - return rootInfo; + return rootInfo; } int remountFS(EncFS_Context *ctx) { - rDebug("Attempting to reinitialize filesystem"); + rDebug("Attempting to reinitialize filesystem"); - RootPtr rootInfo = initFS( ctx, ctx->opts ); - if(rootInfo) - { - ctx->setRoot(rootInfo->root); - return 0; - } else - { - rInfo(_("Remount failed")); - return -EACCES; - } + RootPtr rootInfo = initFS( ctx, ctx->opts ); + if(rootInfo) + { + ctx->setRoot(rootInfo->root); + return 0; + } else + { + rInfo(_("Remount failed")); + return -EACCES; + } } diff --git a/encfs/FileUtils.h b/encfs/FileUtils.h index b852ee7..febe328 100644 --- a/encfs/FileUtils.h +++ b/encfs/FileUtils.h @@ -44,96 +44,96 @@ class DirNode; struct EncFS_Root { - boost::shared_ptr cipher; - CipherKey volumeKey; - boost::shared_ptr root; + boost::shared_ptr cipher; + CipherKey volumeKey; + boost::shared_ptr root; - EncFS_Root(); - ~EncFS_Root(); + EncFS_Root(); + ~EncFS_Root(); }; typedef boost::shared_ptr RootPtr; enum ConfigMode { - Config_Prompt, - Config_Standard, - Config_Paranoia + Config_Prompt, + Config_Standard, + Config_Paranoia }; struct EncFS_Opts { - std::string rootDir; - bool createIfNotFound; // create filesystem if not found - bool idleTracking; // turn on idle monitoring of filesystem - bool mountOnDemand; // mounting on-demand + std::string rootDir; + bool createIfNotFound; // create filesystem if not found + bool idleTracking; // turn on idle monitoring of filesystem + bool mountOnDemand; // mounting on-demand - bool checkKey; // check crypto key decoding - bool forceDecode; // force decode on MAC block failures + bool checkKey; // check crypto key decoding + bool forceDecode; // force decode on MAC block failures - std::string passwordProgram; // path to password program (or empty) - bool useStdin; // read password from stdin rather then prompting - bool annotate; // print annotation line prompt to stderr. + std::string passwordProgram; // path to password program (or empty) + bool useStdin; // read password from stdin rather then prompting + bool annotate; // print annotation line prompt to stderr. - bool ownerCreate; // set owner of new files to caller + bool ownerCreate; // set owner of new files to caller - bool reverseEncryption; // Reverse encryption + bool reverseEncryption; // Reverse encryption - ConfigMode configMode; + ConfigMode configMode; - EncFS_Opts() - { - createIfNotFound = true; - idleTracking = false; - mountOnDemand = false; - checkKey = true; - forceDecode = false; - useStdin = false; - annotate = false; - ownerCreate = false; - reverseEncryption = false; - configMode = Config_Prompt; - } + EncFS_Opts() + { + createIfNotFound = true; + idleTracking = false; + mountOnDemand = false; + checkKey = true; + forceDecode = false; + useStdin = false; + annotate = false; + ownerCreate = false; + reverseEncryption = false; + configMode = Config_Prompt; + } }; /* Read existing config file. Looks for any supported configuration version. -*/ + */ ConfigType readConfig( const std::string &rootDir, - const boost::shared_ptr &config ); + const boost::shared_ptr &config ); /* Save the configuration. Saves back as the same configuration type as was read from. -*/ + */ bool saveConfig( ConfigType type, const std::string &rootdir, - const boost::shared_ptr &config ); + const boost::shared_ptr &config ); class EncFS_Context; RootPtr initFS( EncFS_Context *ctx, const boost::shared_ptr &opts ); RootPtr createV6Config( EncFS_Context *ctx, - const boost::shared_ptr &opts ); + const boost::shared_ptr &opts ); void showFSInfo( const boost::shared_ptr &config ); bool readV4Config( const char *configFile, - const boost::shared_ptr &config, - struct ConfigInfo *); + const boost::shared_ptr &config, + struct ConfigInfo *); bool writeV4Config( const char *configFile, - const boost::shared_ptr &config); + const boost::shared_ptr &config); bool readV5Config( const char *configFile, - const boost::shared_ptr &config, - struct ConfigInfo *); + const boost::shared_ptr &config, + struct ConfigInfo *); bool writeV5Config( const char *configFile, - const boost::shared_ptr &config); + const boost::shared_ptr &config); bool readV6Config( const char *configFile, - const boost::shared_ptr &config, - struct ConfigInfo *); + const boost::shared_ptr &config, + struct ConfigInfo *); bool writeV6Config( const char *configFile, - const boost::shared_ptr &config); + const boost::shared_ptr &config); #endif