replace boost serialization with tinyxml2

This commit is contained in:
Valient Gough 2016-04-14 23:11:45 -07:00
parent bbf3d6f679
commit e78d1659e3
No known key found for this signature in database
GPG Key ID: B515DCEB95967051
17 changed files with 611 additions and 289 deletions

View File

@ -48,11 +48,8 @@ add_definitions (-D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=26)
find_package (OpenSSL REQUIRED) find_package (OpenSSL REQUIRED)
include_directories (${OPENSSL_INCLUDE_DIR}) include_directories (${OPENSSL_INCLUDE_DIR})
find_package(Boost find_package (TinyXML REQUIRED)
1.34.0 include_directories (${TINYXML_INCLUDE_DIR})
REQUIRED
COMPONENTS serialization)
include_directories (${Boost_INCLUDE_DIRS})
find_package (RLog REQUIRED) find_package (RLog REQUIRED)
add_definitions (-DRLOG_COMPONENT="encfs") add_definitions (-DRLOG_COMPONENT="encfs")
@ -130,6 +127,7 @@ set(SOURCE_FILES
encfs/readpassphrase.cpp encfs/readpassphrase.cpp
encfs/SSL_Cipher.cpp encfs/SSL_Cipher.cpp
encfs/StreamNameIO.cpp encfs/StreamNameIO.cpp
encfs/XmlReader.cpp
) )
add_library(encfs SHARED ${SOURCE_FILES}) add_library(encfs SHARED ${SOURCE_FILES})
set_property(TARGET encfs PROPERTY VERSION ${ENCFS_VERSION}) set_property(TARGET encfs PROPERTY VERSION ${ENCFS_VERSION})
@ -137,7 +135,7 @@ set_property(TARGET encfs PROPERTY SOVERSION ${ENCFS_SOVERSION})
target_link_libraries(encfs target_link_libraries(encfs
${FUSE_LIBRARIES} ${FUSE_LIBRARIES}
${OPENSSL_LIBRARIES} ${OPENSSL_LIBRARIES}
${Boost_LIBRARIES} ${TINYXML_LIBRARIES}
${RLOG_LIBRARIES} ${RLOG_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT} ${CMAKE_THREAD_LIBS_INIT}
) )

View File

@ -41,7 +41,7 @@ Dependencies
EncFS depends on a number of libraries: EncFS depends on a number of libraries:
openssl fuse boost-serialization gettext libintl librlog openssl fuse tinyxml2 gettext libintl librlog
Compiling on Debian and Ubuntu Compiling on Debian and Ubuntu
============================== ==============================

View File

@ -4,8 +4,7 @@ machine:
dependencies: dependencies:
pre: pre:
- sudo apt-get update - sudo apt-get install cmake libfuse-dev librlog-dev libgettextpo-dev libtinyxml2-dev
- sudo apt-get install cmake libfuse-dev librlog-dev libgettextpo-dev
- bash ./ci/install-gcc.sh - bash ./ci/install-gcc.sh
test: test:

26
cmake/FindTinyXML.cmake Normal file
View File

@ -0,0 +1,26 @@
# - Find TinyXML
# Find the native TinyXML includes and library
#
# TINYXML_FOUND - True if TinyXML found.
# TINYXML_INCLUDE_DIR - where to find tinyxml.h, etc.
# TINYXML_LIBRARIES - List of libraries when using TinyXML.
#
IF( TINYXML_INCLUDE_DIR )
# Already in cache, be silent
SET( TinyXML_FIND_QUIETLY TRUE )
ENDIF( TINYXML_INCLUDE_DIR )
FIND_PATH( TINYXML_INCLUDE_DIR "tinyxml2.h"
PATH_SUFFIXES "tinyxml2" )
FIND_LIBRARY( TINYXML_LIBRARIES
NAMES "tinyxml2"
PATH_SUFFIXES "tinyxml2" )
# handle the QUIETLY and REQUIRED arguments and set TINYXML_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE( "FindPackageHandleStandardArgs" )
FIND_PACKAGE_HANDLE_STANDARD_ARGS( "TinyXML" DEFAULT_MSG TINYXML_INCLUDE_DIR TINYXML_LIBRARIES )
MARK_AS_ADVANCED( TINYXML_INCLUDE_DIR TINYXML_LIBRARIES )

2
devmode Normal file → Executable file
View File

@ -1,4 +1,4 @@
# Script which sets up the CMake build for Debug mode. # Script which sets up the CMake build for Debug mode.
# After running, chdir to the build subdir ane run "make" # After running, chdir to the build subdir ane run "make"
mkdir build mkdir build
cd build && cmake .. -DCMAKE_BUILD_TYPE=Debug $@ cd build && cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-fsanitize=address" $@

View File

@ -4,7 +4,7 @@ FROM ubuntu
# Do system updates and install dependencies # Do system updates and install dependencies
RUN apt-get update RUN apt-get update
RUN apt-get -y upgrade RUN apt-get -y upgrade
RUN sudo apt-get -y install git wget autopoint libfuse-dev libboost-serialization-dev RUN sudo apt-get -y install git wget autopoint libfuse-dev libtinyxml2-dev
RUN apt-get clean RUN apt-get clean
# Download Drone.io # Download Drone.io

View File

@ -31,10 +31,10 @@ RUN apt-get -y upgrade \
&& apt-get -y install \ && apt-get -y install \
git \ git \
libfuse-dev \ libfuse-dev \
libboost-serialization-dev \
libssl-dev \ libssl-dev \
librlog-dev \ librlog-dev \
gettext \ gettext \
libgettextpo-dev \ libgettextpo-dev \
libtinyxml2-dev \
&& apt-get clean && apt-get clean

View File

@ -21,6 +21,7 @@
#ifndef _FSConfig_incl_ #ifndef _FSConfig_incl_
#define _FSConfig_incl_ #define _FSConfig_incl_
#include <string>
#include <vector> #include <vector>
#include "encfs.h" #include "encfs.h"
@ -54,12 +55,13 @@ struct EncFSConfig {
rel::Interface cipherIface; rel::Interface cipherIface;
// interface used for file name coding // interface used for file name coding
rel::Interface nameIface; rel::Interface nameIface;
int keySize; // reported in bits int keySize; // reported in bits
int blockSize; // reported in bytes int blockSize; // reported in bytes
std::vector<unsigned char> keyData; std::vector<unsigned char> keyData;
std::vector<unsigned char> salt; std::vector<unsigned char> salt;
int kdfIterations; int kdfIterations;
long desiredKDFDuration; long desiredKDFDuration;

View File

@ -24,12 +24,6 @@
#endif #endif
#define _BSD_SOURCE // pick up setenv on RH7.3 #define _BSD_SOURCE // pick up setenv on RH7.3
#include <boost/version.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/binary_object.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/split_free.hpp>
#include <fcntl.h> #include <fcntl.h>
#include <rlog/Error.h> #include <rlog/Error.h>
#include <rlog/rlog.h> #include <rlog/rlog.h>
@ -45,6 +39,7 @@
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <list> #include <list>
#include <tinyxml2.h>
#include <vector> #include <vector>
#include "BlockNameIO.h" #include "BlockNameIO.h"
@ -59,7 +54,9 @@
#include "Interface.h" #include "Interface.h"
#include "NameIO.h" #include "NameIO.h"
#include "Range.h" #include "Range.h"
#include "XmlReader.h"
#include "autosprintf.h" #include "autosprintf.h"
#include "base64.h"
#include "config.h" #include "config.h"
#include "i18n.h" #include "i18n.h"
#include "intl/gettext.h" #include "intl/gettext.h"
@ -73,7 +70,6 @@ using namespace rel;
using namespace rlog; using namespace rlog;
using namespace std; using namespace std;
using gnu::autosprintf; using gnu::autosprintf;
namespace serial = boost::serialization;
static const int DefaultBlockSize = 1024; static const int DefaultBlockSize = 1024;
// The maximum length of text passwords. If longer are needed, // The maximum length of text passwords. If longer are needed,
@ -108,9 +104,8 @@ struct ConfigInfo {
const char *fileName; const char *fileName;
ConfigType type; ConfigType type;
const char *environmentOverride; const char *environmentOverride;
bool (*loadFunc)(const char *fileName, const shared_ptr<EncFSConfig> &config, bool (*loadFunc)(const char *fileName, EncFSConfig *config, ConfigInfo *cfg);
ConfigInfo *cfg); bool (*saveFunc)(const char *fileName, const EncFSConfig *config);
bool (*saveFunc)(const char *fileName, const shared_ptr<EncFSConfig> &config);
int currentSubVersion; int currentSubVersion;
int defaultSubVersion; int defaultSubVersion;
} ConfigFileMapping[] = { } ConfigFileMapping[] = {
@ -127,121 +122,6 @@ struct ConfigInfo {
{".encfs", Config_Prehistoric, NULL, NULL, NULL, 0, 0}, {".encfs", Config_Prehistoric, NULL, NULL, NULL, 0, 0},
{NULL, Config_None, NULL, NULL, NULL, 0, 0}}; {NULL, Config_None, NULL, NULL, NULL, 0, 0}};
#include "boost-versioning.h" // IWYU pragma: keep
// define serialization helpers
namespace boost {
namespace serialization {
template <class Archive>
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);
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 = cfg.keyData.size();
ar << make_nvp("encodedKeySize", encodedSize);
ar << make_nvp("encodedKeyData",
serial::make_binary_object(cfg.getKeyData(), encodedSize));
// 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 <class Archive>
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 <class Archive>
void serialize(Archive &ar, EncFSConfig &cfg, unsigned int version) {
split_free(ar, cfg, version);
}
template <class Archive>
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());
}
}
}
EncFS_Root::EncFS_Root() {} EncFS_Root::EncFS_Root() {}
EncFS_Root::~EncFS_Root() {} EncFS_Root::~EncFS_Root() {}
@ -330,7 +210,7 @@ bool userAllowMkdir(int promptno, const char *path, mode_t mode) {
* Load config file by calling the load function on the filename * Load config file by calling the load function on the filename
*/ */
ConfigType readConfig_load(ConfigInfo *nm, const char *path, ConfigType readConfig_load(ConfigInfo *nm, const char *path,
const shared_ptr<EncFSConfig> &config) { EncFSConfig *config) {
if (nm->loadFunc) { if (nm->loadFunc) {
try { try {
if ((*nm->loadFunc)(path, config, nm)) { if ((*nm->loadFunc)(path, config, nm)) {
@ -354,8 +234,7 @@ ConfigType readConfig_load(ConfigInfo *nm, const char *path,
* Try to locate the config file * Try to locate the config file
* Tries the most recent format first, then looks for older versions * Tries the most recent format first, then looks for older versions
*/ */
ConfigType readConfig(const string &rootDir, ConfigType readConfig(const string &rootDir, EncFSConfig *config) {
const shared_ptr<EncFSConfig> &config) {
ConfigInfo *nm = ConfigFileMapping; ConfigInfo *nm = ConfigFileMapping;
while (nm->fileName) { while (nm->fileName) {
// allow environment variable to override default config path // allow environment variable to override default config path
@ -386,32 +265,96 @@ ConfigType readConfig(const string &rootDir,
* Read config file in current "V6" XML format, normally named ".encfs6.xml" * Read config file in current "V6" XML format, normally named ".encfs6.xml"
* This format is in use since Apr 13, 2008 (commit 6d081f5c) * This format is in use since Apr 13, 2008 (commit 6d081f5c)
*/ */
bool readV6Config(const char *configFile, const shared_ptr<EncFSConfig> &config, // Read a boost::serialization config file using an Xml reader..
bool readV6Config(const char *configFile, EncFSConfig *cfg,
ConfigInfo *info) { ConfigInfo *info) {
(void)info; (void)info;
ifstream st(configFile); XmlReader rdr;
if (st.is_open()) { if (!rdr.load(configFile)) {
try { rError("Failed to load config file %s", configFile);
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 {
rInfo("Failed to load config file %s", configFile);
return false; return false;
} }
XmlValuePtr serialization = rdr["boost_serialization"];
XmlValuePtr config = (*serialization)["cfg"];
if (!config) {
config = (*serialization)["config"];
}
if (!config) {
rError("Unable to find XML configuration in file %s", configFile);
return false;
}
int version;
if (!config->read("version", &version) &&
!config->read("@version", &version)) {
rError("Unable to find version in config file");
return false;
}
// version numbering was complicated by boost::archive
if (version == 20 || version >= 20100713) {
rDebug("found new serialization format");
cfg->subVersion = version;
} else if (version == 26800) {
rDebug("found 20080816 version");
cfg->subVersion = 20080816;
} else if (version == 26797) {
rDebug("found 20080813");
cfg->subVersion = 20080813;
} else if (version < V5SubVersion) {
rError("Invalid version %d - please fix config file", version);
} else {
rInfo("Boost <= 1.41 compatibility mode");
cfg->subVersion = version;
}
rDebug("subVersion = %d", cfg->subVersion);
config->read("creator", &cfg->creator);
config->read("cipherAlg", &cfg->cipherIface);
config->read("nameAlg", &cfg->nameIface);
config->read("keySize", &cfg->keySize);
config->read("blockSize", &cfg->blockSize);
config->read("uniqueIV", &cfg->uniqueIV);
config->read("chainedNameIV", &cfg->chainedNameIV);
config->read("externalIVChaining", &cfg->externalIVChaining);
config->read("blockMACBytes", &cfg->blockMACBytes);
config->read("blockMACRandBytes", &cfg->blockMACRandBytes);
config->read("allowHoles", &cfg->allowHoles);
int encodedSize;
config->read("encodedKeySize", &encodedSize);
unsigned char *key = new unsigned char[encodedSize];
config->readB64("encodedKeyData", key, encodedSize);
cfg->assignKeyData(key, encodedSize);
delete[] key;
if (cfg->subVersion >= 20080816) {
int saltLen;
config->read("saltLen", &saltLen);
unsigned char *salt = new unsigned char[saltLen];
config->readB64("saltData", salt, saltLen);
cfg->assignSaltData(salt, saltLen);
delete[] salt;
config->read("kdfIterations", &cfg->kdfIterations);
config->read("desiredKDFDuration", &cfg->desiredKDFDuration);
} else {
cfg->kdfIterations = 16;
cfg->desiredKDFDuration = NormalKDFDuration;
}
return true;
} }
/** /**
* Read config file in deprecated "V5" format, normally named ".encfs5" * Read config file in deprecated "V5" format, normally named ".encfs5"
* This format has been used before Apr 13, 2008 * This format has been used before Apr 13, 2008
*/ */
bool readV5Config(const char *configFile, const shared_ptr<EncFSConfig> &config, bool readV5Config(const char *configFile, EncFSConfig *config,
ConfigInfo *info) { ConfigInfo *info) {
bool ok = false; bool ok = false;
@ -466,7 +409,7 @@ bool readV5Config(const char *configFile, const shared_ptr<EncFSConfig> &config,
* Read config file in deprecated "V4" format, normally named ".encfs4" * Read config file in deprecated "V4" format, normally named ".encfs4"
* This format has been used before Jan 7, 2008 * This format has been used before Jan 7, 2008
*/ */
bool readV4Config(const char *configFile, const shared_ptr<EncFSConfig> &config, bool readV4Config(const char *configFile, EncFSConfig *config,
ConfigInfo *info) { ConfigInfo *info) {
bool ok = false; bool ok = false;
@ -503,7 +446,7 @@ bool readV4Config(const char *configFile, const shared_ptr<EncFSConfig> &config,
} }
bool saveConfig(ConfigType type, const string &rootDir, bool saveConfig(ConfigType type, const string &rootDir,
const shared_ptr<EncFSConfig> &config) { const EncFSConfig *config) {
bool ok = false; bool ok = false;
ConfigInfo *nm = ConfigFileMapping; ConfigInfo *nm = ConfigFileMapping;
@ -530,31 +473,93 @@ bool saveConfig(ConfigType type, const string &rootDir,
return ok; return ok;
} }
bool writeV6Config(const char *configFile, template <typename T>
const shared_ptr<EncFSConfig> &config) { tinyxml2::XMLElement *addEl(tinyxml2::XMLDocument &doc,
ofstream st(configFile); tinyxml2::XMLNode *parent, const char *name,
if (!st.is_open()) return false; T value) {
auto el = doc.NewElement(name);
st << *config; el->SetText(value);
return true; parent->InsertEndChild(el);
return el;
} }
std::ostream &operator<<(std::ostream &st, const EncFSConfig &cfg) { template <>
boost::archive::xml_oarchive oa(st); tinyxml2::XMLElement *addEl<>(tinyxml2::XMLDocument &doc,
oa << BOOST_SERIALIZATION_NVP(cfg); tinyxml2::XMLNode *parent, const char *name,
Interface iface) {
auto el = doc.NewElement(name);
return st; auto n = doc.NewElement("name");
n->SetText(iface.name().c_str());
el->InsertEndChild(n);
auto major = doc.NewElement("major");
major->SetText(iface.current());
el->InsertEndChild(major);
auto minor = doc.NewElement("minor");
minor->SetText(iface.revision());
el->InsertEndChild(minor);
parent->InsertEndChild(el);
return el;
} }
std::istream &operator>>(std::istream &st, EncFSConfig &cfg) { template <>
boost::archive::xml_iarchive ia(st); tinyxml2::XMLElement *addEl<>(tinyxml2::XMLDocument &doc,
ia >> BOOST_SERIALIZATION_NVP(cfg); tinyxml2::XMLNode *parent, const char *name,
std::vector<unsigned char> data) {
string v = string("\n") + B64StandardEncode(data) + "\n";
return addEl(doc, parent, name, v.c_str());
}
return st; bool writeV6Config(const char *configFile, const EncFSConfig *cfg) {
tinyxml2::XMLDocument doc;
// Various static tags are included to make the output compatible with
// older boost-based readers.
doc.InsertEndChild(doc.NewDeclaration(nullptr));
doc.InsertEndChild(doc.NewUnknown("DOCTYPE boost_serialization"));
auto header = doc.NewElement("boost_serialization");
header->SetAttribute("signature", "serialization::archive");
header->SetAttribute("version", "7");
doc.InsertEndChild(header);
auto config = doc.NewElement("cfg");
config->SetAttribute("class_id", "0");
config->SetAttribute("tracking_level", "0");
config->SetAttribute("version", "20");
header->InsertEndChild(config);
addEl(doc, config, "version", V6SubVersion);
addEl(doc, config, "creator", cfg->creator.c_str());
auto cipherAlg = addEl(doc, config, "cipherAlg", cfg->cipherIface);
cipherAlg->SetAttribute("class_id", "1");
cipherAlg->SetAttribute("tracking_level", "0");
cipherAlg->SetAttribute("version", "0");
addEl(doc, config, "nameAlg", cfg->nameIface);
addEl(doc, config, "keySize", cfg->keySize);
addEl(doc, config, "blockSize", cfg->blockSize);
addEl(doc, config, "uniqueIV", cfg->uniqueIV);
addEl(doc, config, "chainedNameIV", cfg->chainedNameIV);
addEl(doc, config, "externalIVChaining", cfg->externalIVChaining);
addEl(doc, config, "blockMACBytes", cfg->blockMACBytes);
addEl(doc, config, "blockMACRandBytes", cfg->blockMACRandBytes);
addEl(doc, config, "allowHoles", cfg->allowHoles);
addEl(doc, config, "encodedKeySize", (int)cfg->keyData.size());
addEl(doc, config, "encodedKeyData", cfg->keyData);
addEl(doc, config, "saltLen", (int)cfg->salt.size());
addEl(doc, config, "saltData", cfg->salt);
addEl(doc, config, "kdfIterations", cfg->kdfIterations);
addEl(doc, config, "desiredKDFDuration", (int)cfg->desiredKDFDuration);
auto err = doc.SaveFile(configFile, false);
return err == tinyxml2::XML_SUCCESS;
} }
bool writeV5Config(const char *configFile, bool writeV5Config(const char *configFile,
const shared_ptr<EncFSConfig> &config) { const EncFSConfig *config) {
ConfigReader cfg; ConfigReader cfg;
cfg["creator"] << config->creator; cfg["creator"] << config->creator;
@ -576,7 +581,7 @@ bool writeV5Config(const char *configFile,
} }
bool writeV4Config(const char *configFile, bool writeV4Config(const char *configFile,
const shared_ptr<EncFSConfig> &config) { const EncFSConfig *config) {
ConfigReader cfg; ConfigReader cfg;
cfg["cipher"] << config->cipherIface; cfg["cipher"] << config->cipherIface;
@ -1125,7 +1130,7 @@ RootPtr createV6Config(EncFS_Context *ctx, const shared_ptr<EncFS_Opts> &opts) {
// xgroup(setup) // xgroup(setup)
cout << _("Configuration finished. The filesystem to be created has\n" cout << _("Configuration finished. The filesystem to be created has\n"
"the following properties:") << endl; "the following properties:") << endl;
showFSInfo(config); showFSInfo(config.get());
if (config->externalIVChaining) { if (config->externalIVChaining) {
cout << _("-------------------------- WARNING --------------------------\n") cout << _("-------------------------- WARNING --------------------------\n")
@ -1175,7 +1180,7 @@ RootPtr createV6Config(EncFS_Context *ctx, const shared_ptr<EncFS_Opts> &opts) {
return rootInfo; return rootInfo;
} }
if (!saveConfig(Config_V6, rootDir, config)) return rootInfo; if (!saveConfig(Config_V6, rootDir, config.get())) return rootInfo;
// fill in config struct // fill in config struct
shared_ptr<NameIO> nameCoder = shared_ptr<NameIO> nameCoder =
@ -1208,7 +1213,7 @@ RootPtr createV6Config(EncFS_Context *ctx, const shared_ptr<EncFS_Opts> &opts) {
return rootInfo; return rootInfo;
} }
void showFSInfo(const shared_ptr<EncFSConfig> &config) { void showFSInfo(const EncFSConfig *config) {
shared_ptr<Cipher> cipher = Cipher::New(config->cipherIface, -1); shared_ptr<Cipher> cipher = Cipher::New(config->cipherIface, -1);
{ {
cout << autosprintf( cout << autosprintf(
@ -1517,7 +1522,7 @@ RootPtr initFS(EncFS_Context *ctx, const shared_ptr<EncFS_Opts> &opts) {
RootPtr rootInfo; RootPtr rootInfo;
shared_ptr<EncFSConfig> config(new EncFSConfig); shared_ptr<EncFSConfig> config(new EncFSConfig);
if (readConfig(opts->rootDir, config) != Config_None) { if (readConfig(opts->rootDir, config.get()) != Config_None) {
if (config->blockMACBytes == 0 && opts->requireMac) { if (config->blockMACBytes == 0 && opts->requireMac) {
cout << _( cout << _(
"The configuration disabled MAC, but you passed --require-macs\n"); "The configuration disabled MAC, but you passed --require-macs\n");

View File

@ -69,11 +69,11 @@ enum ConfigMode { Config_Prompt, Config_Standard, Config_Paranoia };
*/ */
struct EncFS_Opts { struct EncFS_Opts {
std::string rootDir; std::string rootDir;
std::string mountPoint; // where to make filesystem visible std::string mountPoint; // where to make filesystem visible
bool createIfNotFound; // create filesystem if not found bool createIfNotFound; // create filesystem if not found
bool idleTracking; // turn on idle monitoring of filesystem bool idleTracking; // turn on idle monitoring of filesystem
bool mountOnDemand; // mounting on-demand bool mountOnDemand; // mounting on-demand
bool delayMount; // delay initial mount bool delayMount; // delay initial mount
bool checkKey; // check crypto key decoding bool checkKey; // check crypto key decoding
bool forceDecode; // force decode on MAC block failures bool forceDecode; // force decode on MAC block failures
@ -118,15 +118,14 @@ struct EncFS_Opts {
/* /*
Read existing config file. Looks for any supported configuration version. Read existing config file. Looks for any supported configuration version.
*/ */
ConfigType readConfig(const std::string &rootDir, ConfigType readConfig(const std::string &rootDir, EncFSConfig *config);
const shared_ptr<EncFSConfig> &config);
/* /*
Save the configuration. Saves back as the same configuration type as was Save the configuration. Saves back as the same configuration type as was
read from. read from.
*/ */
bool saveConfig(ConfigType type, const std::string &rootdir, bool saveConfig(ConfigType type, const std::string &rootdir,
const shared_ptr<EncFSConfig> &config); const EncFSConfig *config);
class EncFS_Context; class EncFS_Context;
@ -134,21 +133,18 @@ RootPtr initFS(EncFS_Context *ctx, const shared_ptr<EncFS_Opts> &opts);
RootPtr createV6Config(EncFS_Context *ctx, const shared_ptr<EncFS_Opts> &opts); RootPtr createV6Config(EncFS_Context *ctx, const shared_ptr<EncFS_Opts> &opts);
void showFSInfo(const shared_ptr<EncFSConfig> &config); void showFSInfo(const EncFSConfig *config);
bool readV4Config(const char *configFile, const shared_ptr<EncFSConfig> &config, bool readV4Config(const char *configFile, EncFSConfig *config,
struct ConfigInfo *); struct ConfigInfo *);
bool writeV4Config(const char *configFile, bool writeV4Config(const char *configFile, const EncFSConfig *config);
const shared_ptr<EncFSConfig> &config);
bool readV5Config(const char *configFile, const shared_ptr<EncFSConfig> &config, bool readV5Config(const char *configFile, EncFSConfig *config,
struct ConfigInfo *); struct ConfigInfo *);
bool writeV5Config(const char *configFile, bool writeV5Config(const char *configFile, const EncFSConfig *config);
const shared_ptr<EncFSConfig> &config);
bool readV6Config(const char *configFile, const shared_ptr<EncFSConfig> &config, bool readV6Config(const char *configFile, EncFSConfig *config,
struct ConfigInfo *); struct ConfigInfo *);
bool writeV6Config(const char *configFile, bool writeV6Config(const char *configFile, const EncFSConfig *config);
const shared_ptr<EncFSConfig> &config);
#endif #endif

192
encfs/XmlReader.cpp Normal file
View File

@ -0,0 +1,192 @@
/*****************************************************************************
* Author: Valient Gough <vgough@pobox.com>
*
*****************************************************************************
* Copyright (c) 2012-2013, Valient Gough
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "XmlReader.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <algorithm>
#include <cstring>
#include <map>
#include <tinyxml2.h>
#include <rlog/Error.h>
#include <rlog/rlog.h>
#include "base64.h"
#include "Interface.h"
#include "shared_ptr.h"
XmlValue::~XmlValue() {}
XmlValuePtr XmlValue::operator[](const char *path) const { return find(path); }
XmlValuePtr XmlValue::find(const char *path) const {
// Shouldn't get here.
rError("in XmlValue::find(%s)", path);
return XmlValuePtr();
}
bool XmlValue::read(const char *path, std::string *out) const {
XmlValuePtr value = find(path);
if (!value) return false;
*out = value->text();
return true;
}
bool XmlValue::read(const char *path, int *out) const {
XmlValuePtr value = find(path);
if (!value) return false;
*out = atoi(value->text().c_str());
return true;
}
bool XmlValue::read(const char *path, long *out) const {
XmlValuePtr value = find(path);
if (!value) return false;
*out = atol(value->text().c_str());
return true;
}
bool XmlValue::read(const char *path, double *out) const {
XmlValuePtr value = find(path);
if (!value) return false;
*out = atof(value->text().c_str());
return true;
}
bool XmlValue::read(const char *path, bool *out) const {
XmlValuePtr value = find(path);
if (!value) return false;
*out = atoi(value->text().c_str());
return true;
}
bool XmlValue::readB64(const char *path, unsigned char *data, int length) const {
XmlValuePtr value = find(path);
if (!value) return false;
std::string s = value->text();
s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end());
s.erase(s.find_last_not_of("=") + 1);
int decodedSize = B64ToB256Bytes(s.size());
if (decodedSize != length) {
rError("decoding bytes len %d, expecting output len %d, got %d", s.size(),
length, decodedSize);
return false;
}
if (!B64StandardDecode(data, (unsigned char *)s.data(), s.size())) {
rError("B64 decode failure on \"%s\"", s.c_str());
return false;
}
return true;
}
bool XmlValue::read(const char *path, rel::Interface *out) const {
XmlValuePtr node = find(path);
if (!node) return false;
bool ok = node->read("name", &out->name()) &&
node->read("major", &out->current()) &&
node->read("minor", &out->revision());
return ok;
}
std::string safeValueForNode(const tinyxml2::XMLElement *element) {
std::string value;
if (element == NULL) return value;
const tinyxml2::XMLNode *child = element->FirstChild();
if (child) {
const tinyxml2::XMLText *childText = child->ToText();
if (childText) value = childText->Value();
}
return value;
}
class XmlNode : virtual public XmlValue {
const tinyxml2::XMLElement *element;
public:
XmlNode(const tinyxml2::XMLElement *element_)
: XmlValue(safeValueForNode(element_)), element(element_) {}
virtual ~XmlNode() {}
virtual XmlValuePtr find(const char *name) const {
if (name[0] == '@') {
const char *value = element->Attribute(name + 1);
if (value)
return XmlValuePtr(new XmlValue(value));
else
return XmlValuePtr();
} else {
const tinyxml2::XMLElement *el = element->FirstChildElement(name);
if (el)
return XmlValuePtr(new XmlNode(el));
else
return XmlValuePtr();
}
}
};
struct XmlReader::XmlReaderData {
shared_ptr<tinyxml2::XMLDocument> doc;
};
XmlReader::XmlReader() : pd(new XmlReaderData()) {}
XmlReader::~XmlReader() {}
bool XmlReader::load(const char *fileName) {
pd->doc.reset(new tinyxml2::XMLDocument());
auto err = pd->doc->LoadFile(fileName);
return err == tinyxml2::XML_SUCCESS;
}
XmlValuePtr XmlReader::operator[](const char *name) const {
tinyxml2::XMLNode *node = pd->doc->FirstChildElement(name);
if (node == NULL) {
rError("Xml node %s not found", name);
return XmlValuePtr(new XmlValue());
}
tinyxml2::XMLElement *element = node->ToElement();
if (element == NULL) {
rError("Xml node %s not element", name);
return XmlValuePtr(new XmlValue());
}
return XmlValuePtr(new XmlNode(element));
}

72
encfs/XmlReader.h Normal file
View File

@ -0,0 +1,72 @@
/*****************************************************************************
* Author: Valient Gough <vgough@pobox.com>
*
*****************************************************************************
* Copyright (c) 2012, Valient Gough
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _XmlReader_incl_
#define _XmlReader_incl_
#include <string>
#include "Interface.h"
#include "shared_ptr.h"
class XmlValue;
typedef shared_ptr<XmlValue> XmlValuePtr;
class XmlValue {
std::string value;
public:
XmlValue() {}
XmlValue(const std::string &value) { this->value = value; }
virtual ~XmlValue();
XmlValuePtr operator[](const char *path) const;
const std::string &text() const { return value; }
bool read(const char *path, std::string *out) const;
bool readB64(const char *path, unsigned char *out, int length) const;
bool read(const char *path, int *out) const;
bool read(const char *path, long *out) const;
bool read(const char *path, double *out) const;
bool read(const char *path, bool *out) const;
bool read(const char *path, rel::Interface *out) const;
protected:
virtual XmlValuePtr find(const char *name) const;
};
class XmlReader {
public:
XmlReader();
~XmlReader();
bool load(const char *fileName);
XmlValuePtr operator[](const char *name) const;
private:
struct XmlReaderData;
shared_ptr<XmlReaderData> pd;
};
#endif

View File

@ -20,8 +20,11 @@
#include "base64.h" #include "base64.h"
#include <cstdlib>
#include <ctype.h> #include <ctype.h>
#include <rlog/rlog.h>
// change between two powers of two, stored as the low bits of the bytes in the // change between two powers of two, stored as the low bits of the bytes in the
// arrays. // arrays.
// It is the caller's responsibility to make sure the output array is large // It is the caller's responsibility to make sure the output array is large
@ -177,3 +180,99 @@ void AsciiToB32(unsigned char *out, const unsigned char *in, int length) {
*out++ = (unsigned char)lch; *out++ = (unsigned char)lch;
} }
} }
#define WHITESPACE 64
#define EQUALS 65
#define INVALID 66
static const unsigned char d[] = {
66, 66, 66, 66, 66, 66, 66, 66, 66, 64, 66, 66, 66, 66, 66, 66, 66,
66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
66, 66, 66, 66, 66, 66, 66, 66, 66, 62, 66, 66, 66, 63, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, 66, 66, // 50-59
66, 65, 66, 66, 66, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 66, 66, 66,
66, 66, 66, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // 100-109
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51};
bool B64StandardDecode(unsigned char *out, const unsigned char *in, int inLen) {
const unsigned char *end = in + inLen;
size_t buf = 1;
while (in < end) {
unsigned char v = *in++;
if (v > 'z') {
rError("Invalid character: %d", (unsigned int)v);
return false;
}
unsigned char c = d[v];
switch (c) {
case WHITESPACE:
continue; /* skip whitespace */
case INVALID:
rError("Invalid character: %d", (unsigned int)v);
return false; /* invalid input, return error */
case EQUALS: /* pad character, end of data */
in = end;
continue;
default:
buf = buf << 6 | c;
/* If the buffer is full, split it into bytes */
if (buf & 0x1000000) {
*out++ = buf >> 16;
*out++ = buf >> 8;
*out++ = buf;
buf = 1;
}
}
}
if (buf & 0x40000) {
*out++ = buf >> 10;
*out++ = buf >> 2;
} else if (buf & 0x1000) {
*out++ = buf >> 4;
}
return true;
}
// Lookup table for encoding
// If you want to use an alternate alphabet, change the characters here
const static char encodeLookup[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
std::string B64StandardEncode(std::vector<unsigned char> inputBuffer) {
std::string encodedString;
encodedString.reserve(B256ToB64Bytes(inputBuffer.size()));
long temp;
std::vector<unsigned char>::iterator cursor = inputBuffer.begin();
for (size_t idx = 0; idx < inputBuffer.size() / 3; idx++) {
temp = (*cursor++) << 16; // Convert to big endian
temp += (*cursor++) << 8;
temp += (*cursor++);
encodedString.append(1, encodeLookup[(temp & 0x00FC0000) >> 18]);
encodedString.append(1, encodeLookup[(temp & 0x0003F000) >> 12]);
encodedString.append(1, encodeLookup[(temp & 0x00000FC0) >> 6]);
encodedString.append(1, encodeLookup[(temp & 0x0000003F)]);
}
switch (inputBuffer.size() % 3) {
case 1:
temp = (*cursor++) << 16; // Convert to big endian
encodedString.append(1, encodeLookup[(temp & 0x00FC0000) >> 18]);
encodedString.append(1, encodeLookup[(temp & 0x0003F000) >> 12]);
encodedString.append(2, '=');
break;
case 2:
temp = (*cursor++) << 16; // Convert to big endian
temp += (*cursor++) << 8;
encodedString.append(1, encodeLookup[(temp & 0x00FC0000) >> 18]);
encodedString.append(1, encodeLookup[(temp & 0x0003F000) >> 12]);
encodedString.append(1, encodeLookup[(temp & 0x00000FC0) >> 6]);
encodedString.append(1, '=');
break;
}
return encodedString;
}

View File

@ -21,6 +21,9 @@
#ifndef _base64_incl_ #ifndef _base64_incl_
#define _base64_incl_ #define _base64_incl_
#include <string>
#include <vector>
inline int B64ToB256Bytes(int numB64Bytes) { inline int B64ToB256Bytes(int numB64Bytes) {
return (numB64Bytes * 6) / 8; // round down return (numB64Bytes * 6) / 8; // round down
} }
@ -62,4 +65,11 @@ void AsciiToB64(unsigned char *out, const unsigned char *in, int length);
void AsciiToB32(unsigned char *buf, int length); void AsciiToB32(unsigned char *buf, int length);
void AsciiToB32(unsigned char *out, const unsigned char *in, int length); void AsciiToB32(unsigned char *out, const unsigned char *in, int length);
// Decode standard B64 into the output array.
// Used only to decode legacy Boost XML serialized config format.
// The output size must be at least B64ToB256Bytes(inputLen).
bool B64StandardDecode(unsigned char *out, const unsigned char *in, int inputLen);
std::string B64StandardEncode(std::vector<unsigned char> input);
#endif #endif

View File

@ -1,79 +0,0 @@
#ifndef BOOST_VERSIONING_INCL
#define BOOST_VERSIONING_INCL
// This header stores workaround code for dealing with incompatible changes
// made to boost archive/serialization classes.
#if (BOOST_VERSION <= 104100)
// Easy case, boost archive serial numbers are sizeof(int)
BOOST_CLASS_VERSION(EncFSConfig, V6SubVersion)
#else
// starting with boost 1.42, serial numbers change to 8-bit. However to make
// things tricker, the internal comparison is more like 16bit, which makes
// writing backward compatible code very tricky.
// We make a partial specialization of the iserializer class to remove the
// version number checking which would otherwise cause boost::serialization to
// throw an exception if it came across a version that was greater then what
// we specify in BOOST_CLASS_VERSION below. Without this, manual editing
// of the file is needed before boost will allow us to read it.
BOOST_CLASS_VERSION(EncFSConfig, 20)
namespace boost {
namespace archive {
namespace detail {
// Specialize iserializer class in order to get rid of version check
template <class Archive>
class iserializer<Archive, EncFSConfig> : public basic_iserializer {
private:
virtual void destroy(/*const*/ void *address) const {
boost::serialization::access::destroy(static_cast<EncFSConfig *>(address));
}
protected:
explicit iserializer()
: basic_iserializer(boost::serialization::singleton<
BOOST_DEDUCED_TYPENAME boost::serialization::
type_info_implementation<
EncFSConfig>::type>::get_const_instance()) {}
public:
virtual BOOST_DLLEXPORT void load_object_data(
basic_iarchive &ar, void *x,
const unsigned int file_version) const BOOST_USED;
virtual bool class_info() const {
return boost::serialization::implementation_level<EncFSConfig>::value >=
boost::serialization::object_class_info;
}
virtual bool tracking(const unsigned int /* flags */) const {
return boost::serialization::tracking_level<EncFSConfig>::value ==
boost::serialization::track_always ||
(boost::serialization::tracking_level<EncFSConfig>::value ==
boost::serialization::track_selectively &&
serialized_as_pointer());
}
virtual version_type version() const {
return version_type(::boost::serialization::version<EncFSConfig>::value);
}
virtual bool is_polymorphic() const {
return boost::is_polymorphic<EncFSConfig>::value;
}
virtual ~iserializer(){};
};
template <class Archive>
BOOST_DLLEXPORT void iserializer<Archive, EncFSConfig>::load_object_data(
basic_iarchive &ar, void *x, const unsigned int file_version) const {
boost::serialization::serialize_adl(
boost::serialization::smart_cast_reference<Archive &>(ar),
*static_cast<EncFSConfig *>(x), file_version);
}
}
}
}
#endif
#endif // BOOST_VERSIONING_INCL

View File

@ -167,7 +167,7 @@ static int showInfo(int argc, char **argv) {
string rootDir = argv[1]; string rootDir = argv[1];
if (!checkDir(rootDir)) return EXIT_FAILURE; if (!checkDir(rootDir)) return EXIT_FAILURE;
shared_ptr<EncFSConfig> config(new EncFSConfig); EncFSConfig* config = new EncFSConfig;
ConfigType type = readConfig(rootDir, config); ConfigType type = readConfig(rootDir, config);
// show information stored in config.. // show information stored in config..
@ -617,7 +617,7 @@ static int do_chpasswd(bool useStdin, bool annotate, bool checkOnly, int argc, c
string rootDir = argv[1]; string rootDir = argv[1];
if (!checkDir(rootDir)) return EXIT_FAILURE; if (!checkDir(rootDir)) return EXIT_FAILURE;
shared_ptr<EncFSConfig> config(new EncFSConfig); EncFSConfig* config = new EncFSConfig;
ConfigType cfgType = readConfig(rootDir, config); ConfigType cfgType = readConfig(rootDir, config);
if (cfgType == Config_None) { if (cfgType == Config_None) {

View File

@ -16,12 +16,9 @@
* *
*/ */
#include <rlog/Error.h>
#include <rlog/RLogChannel.h>
#include <rlog/StdioNode.h>
#include <rlog/rlog.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <iostream>
#include <list> #include <list>
@ -29,6 +26,11 @@
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <rlog/Error.h>
#include <rlog/RLogChannel.h>
#include <rlog/StdioNode.h>
#include <rlog/rlog.h>
#include "BlockNameIO.h" #include "BlockNameIO.h"
#include "Cipher.h" #include "Cipher.h"
#include "CipherKey.h" #include "CipherKey.h"
@ -132,8 +134,9 @@ static bool testNameCoding(DirNode &dirNode, bool verbose) {
bool runTests(const shared_ptr<Cipher> &cipher, bool verbose) { bool runTests(const shared_ptr<Cipher> &cipher, bool verbose) {
// create a random key // create a random key
if (verbose) if (verbose) {
cerr << "Generating new key, output will be different on each run\n\n"; cerr << "Generating new key, output will be different on each run\n\n";
}
CipherKey key = cipher->newRandomKey(); CipherKey key = cipher->newRandomKey();
if (verbose) cerr << "Testing key save / restore :"; if (verbose) cerr << "Testing key save / restore :";
@ -173,18 +176,17 @@ bool runTests(const shared_ptr<Cipher> &cipher, bool verbose) {
cfg.assignKeyData(keyBuf, encodedKeySize); cfg.assignKeyData(keyBuf, encodedKeySize);
// save config // save config
string data; auto name = std::tmpnam(nullptr);
{ {
ostringstream st; auto ok = writeV6Config(name, &cfg);
st << cfg; rAssert(ok == true);
data = st.str();
} }
// read back in and check everything.. // read back in and check everything..
EncFSConfig cfg2; EncFSConfig cfg2;
{ {
istringstream st(data); auto ok = readV6Config(name, &cfg2, nullptr);
st >> cfg2; rAssert(ok == true);
} }
// check.. // check..