reformat using clang

This commit is contained in:
Valient Gough 2014-10-18 19:19:33 -07:00
parent 744f56b95d
commit b3c851982f
59 changed files with 8004 additions and 9714 deletions

52
.clang-format Normal file
View File

@ -0,0 +1,52 @@
---
Language: Cpp
# BasedOnStyle: Google
AccessModifierOffset: -1
ConstructorInitializerIndentWidth: 4
AlignEscapedNewlinesLeft: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AllowShortFunctionsOnASingleLine: true
AlwaysBreakTemplateDeclarations: true
AlwaysBreakBeforeMultilineStrings: true
BreakBeforeBinaryOperators: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BinPackParameters: true
ColumnLimit: 80
ConstructorInitializerAllOnOneLineOrOnePerLine: true
DerivePointerBinding: true
ExperimentalAutoDetectBinPacking: false
IndentCaseLabels: true
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: false
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakString: 1000
PenaltyBreakFirstLessLess: 120
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerBindsToType: true
SpacesBeforeTrailingComments: 2
Cpp11BracedListStyle: true
Standard: Auto
IndentWidth: 2
TabWidth: 8
UseTab: Never
BreakBeforeBraces: Attach
IndentFunctionDeclarationAfterType: true
SpacesInParentheses: false
SpacesInAngles: false
SpaceInEmptyParentheses: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: true
SpaceBeforeAssignmentOperators: true
ContinuationIndentWidth: 4
CommentPragmas: '^ IWYU pragma:'
SpaceBeforeParens: ControlStatements
...

View File

@ -28,47 +28,37 @@
#include "i18n.h" #include "i18n.h"
template <typename Type> template <typename Type>
inline Type min( Type A, Type B ) inline Type min(Type A, Type B) {
{
return (B < A) ? B : A; return (B < A) ? B : A;
} }
static void clearCache( IORequest &req, int blockSize ) static void clearCache(IORequest &req, int blockSize) {
{
memset(req.data, 0, blockSize); memset(req.data, 0, blockSize);
req.dataLen = 0; req.dataLen = 0;
} }
BlockFileIO::BlockFileIO(int blockSize, const FSConfigPtr &cfg) BlockFileIO::BlockFileIO(int blockSize, const FSConfigPtr &cfg)
: _blockSize( blockSize ) : _blockSize(blockSize), _allowHoles(cfg->config->allowHoles) {
, _allowHoles( cfg->config->allowHoles )
{
rAssert(_blockSize > 1); rAssert(_blockSize > 1);
_cache.data = new unsigned char[_blockSize]; _cache.data = new unsigned char[_blockSize];
} }
BlockFileIO::~BlockFileIO() BlockFileIO::~BlockFileIO() {
{
clearCache(_cache, _blockSize); clearCache(_cache, _blockSize);
delete[] _cache.data; delete[] _cache.data;
} }
ssize_t BlockFileIO::cacheReadOneBlock( const IORequest &req ) const ssize_t BlockFileIO::cacheReadOneBlock(const IORequest &req) const {
{
// we can satisfy the request even if _cache.dataLen is too short, because // we can satisfy the request even if _cache.dataLen is too short, because
// we always request a full block during reads.. // we always request a full block during reads..
if((req.offset == _cache.offset) && (_cache.dataLen != 0)) if ((req.offset == _cache.offset) && (_cache.dataLen != 0)) {
{
// satisfy request from cache // satisfy request from cache
int len = req.dataLen; int len = req.dataLen;
if(_cache.dataLen < len) if (_cache.dataLen < len) len = _cache.dataLen;
len = _cache.dataLen;
memcpy(req.data, _cache.data, len); memcpy(req.data, _cache.data, len);
return len; return len;
} else } else {
{ if (_cache.dataLen > 0) clearCache(_cache, _blockSize);
if(_cache.dataLen > 0)
clearCache( _cache, _blockSize );
// cache results of read -- issue reads for full blocks // cache results of read -- issue reads for full blocks
IORequest tmp; IORequest tmp;
@ -76,8 +66,7 @@ ssize_t BlockFileIO::cacheReadOneBlock( const IORequest &req ) const
tmp.data = _cache.data; tmp.data = _cache.data;
tmp.dataLen = _blockSize; tmp.dataLen = _blockSize;
ssize_t result = readOneBlock(tmp); ssize_t result = readOneBlock(tmp);
if(result > 0) if (result > 0) {
{
_cache.offset = req.offset; _cache.offset = req.offset;
_cache.dataLen = result; // the amount we really have _cache.dataLen = result; // the amount we really have
if (result > req.dataLen) if (result > req.dataLen)
@ -88,34 +77,29 @@ ssize_t BlockFileIO::cacheReadOneBlock( const IORequest &req ) const
} }
} }
bool BlockFileIO::cacheWriteOneBlock( const IORequest &req ) bool BlockFileIO::cacheWriteOneBlock(const IORequest &req) {
{
// cache results of write (before pass-thru, because it may be modified // cache results of write (before pass-thru, because it may be modified
// in-place) // in-place)
memcpy(_cache.data, req.data, req.dataLen); memcpy(_cache.data, req.data, req.dataLen);
_cache.offset = req.offset; _cache.offset = req.offset;
_cache.dataLen = req.dataLen; _cache.dataLen = req.dataLen;
bool ok = writeOneBlock(req); bool ok = writeOneBlock(req);
if(!ok) if (!ok) clearCache(_cache, _blockSize);
clearCache( _cache, _blockSize );
return ok; return ok;
} }
ssize_t BlockFileIO::read( const IORequest &req ) const ssize_t BlockFileIO::read(const IORequest &req) const {
{
rAssert(_blockSize != 0); rAssert(_blockSize != 0);
int partialOffset = req.offset % _blockSize; int partialOffset = req.offset % _blockSize;
off_t blockNum = req.offset / _blockSize; off_t blockNum = req.offset / _blockSize;
ssize_t result = 0; ssize_t result = 0;
if(partialOffset == 0 && req.dataLen <= _blockSize) if (partialOffset == 0 && req.dataLen <= _blockSize) {
{
// read completely within a single block -- can be handled as-is by // read completely within a single block -- can be handled as-is by
// readOneBloc(). // readOneBloc().
return cacheReadOneBlock(req); return cacheReadOneBlock(req);
} else } else {
{
size_t size = req.dataLen; size_t size = req.dataLen;
// if the request is larger then a block, then request each block // if the request is larger then a block, then request each block
@ -126,18 +110,15 @@ ssize_t BlockFileIO::read( const IORequest &req ) const
blockReq.data = NULL; blockReq.data = NULL;
unsigned char *out = req.data; unsigned char *out = req.data;
while( size ) while (size) {
{
blockReq.offset = blockNum * _blockSize; blockReq.offset = blockNum * _blockSize;
// if we're reading a full block, then read directly into the // if we're reading a full block, then read directly into the
// result buffer instead of using a temporary // result buffer instead of using a temporary
if (partialOffset == 0 && size >= (size_t)_blockSize) if (partialOffset == 0 && size >= (size_t)_blockSize)
blockReq.data = out; blockReq.data = out;
else else {
{ if (!mb.data) mb = MemoryPool::allocate(_blockSize);
if(!mb.data)
mb = MemoryPool::allocate( _blockSize );
blockReq.data = mb.data; blockReq.data = mb.data;
} }
@ -158,19 +139,16 @@ ssize_t BlockFileIO::read( const IORequest &req ) const
++blockNum; ++blockNum;
partialOffset = 0; partialOffset = 0;
if(unlikely(readSize < _blockSize)) if (unlikely(readSize < _blockSize)) break;
break;
} }
if(mb.data) if (mb.data) MemoryPool::release(mb);
MemoryPool::release( mb );
} }
return result; return result;
} }
bool BlockFileIO::write( const IORequest &req ) bool BlockFileIO::write(const IORequest &req) {
{
rAssert(_blockSize != 0); rAssert(_blockSize != 0);
off_t fileSize = getSize(); off_t fileSize = getSize();
@ -184,11 +162,9 @@ bool BlockFileIO::write( const IORequest &req )
ssize_t lastBlockSize = fileSize % _blockSize; ssize_t lastBlockSize = fileSize % _blockSize;
off_t lastNonEmptyBlock = lastFileBlock; off_t lastNonEmptyBlock = lastFileBlock;
if(lastBlockSize == 0) if (lastBlockSize == 0) --lastNonEmptyBlock;
--lastNonEmptyBlock;
if( req.offset > fileSize ) if (req.offset > fileSize) {
{
// extend file first to fill hole with 0's.. // extend file first to fill hole with 0's..
const bool forceWrite = false; const bool forceWrite = false;
padFile(fileSize, req.offset, forceWrite); padFile(fileSize, req.offset, forceWrite);
@ -196,11 +172,9 @@ bool BlockFileIO::write( const IORequest &req )
// check against edge cases where we can just let the base class handle the // check against edge cases where we can just let the base class handle the
// request as-is.. // request as-is..
if(partialOffset == 0 && req.dataLen <= _blockSize) if (partialOffset == 0 && req.dataLen <= _blockSize) {
{
// if writing a full block.. pretty safe.. // if writing a full block.. pretty safe..
if( req.dataLen == _blockSize ) if (req.dataLen == _blockSize) return cacheWriteOneBlock(req);
return cacheWriteOneBlock( req );
// if writing a partial block, but at least as much as what is // if writing a partial block, but at least as much as what is
// already there.. // already there..
@ -218,34 +192,28 @@ bool BlockFileIO::write( const IORequest &req )
bool ok = true; bool ok = true;
size_t size = req.dataLen; size_t size = req.dataLen;
unsigned char *inPtr = req.data; unsigned char *inPtr = req.data;
while( size ) while (size) {
{
blockReq.offset = blockNum * _blockSize; blockReq.offset = blockNum * _blockSize;
int toCopy = min((size_t)(_blockSize - partialOffset), size); int toCopy = min((size_t)(_blockSize - partialOffset), size);
// if writing an entire block, or writing a partial block that requires // if writing an entire block, or writing a partial block that requires
// no merging with existing data.. // no merging with existing data..
if( (toCopy == _blockSize) if ((toCopy == _blockSize) ||
||(partialOffset == 0 && blockReq.offset + toCopy >= fileSize)) (partialOffset == 0 && blockReq.offset + toCopy >= fileSize)) {
{
// write directly from buffer // write directly from buffer
blockReq.data = inPtr; blockReq.data = inPtr;
blockReq.dataLen = toCopy; blockReq.dataLen = toCopy;
} else } else {
{
// need a temporary buffer, since we have to either merge or pad // need a temporary buffer, since we have to either merge or pad
// the data. // the data.
if(!mb.data) if (!mb.data) mb = MemoryPool::allocate(_blockSize);
mb = MemoryPool::allocate( _blockSize );
memset(mb.data, 0, _blockSize); memset(mb.data, 0, _blockSize);
blockReq.data = mb.data; blockReq.data = mb.data;
if(blockNum > lastNonEmptyBlock) if (blockNum > lastNonEmptyBlock) {
{
// just pad.. // just pad..
blockReq.dataLen = toCopy + partialOffset; blockReq.dataLen = toCopy + partialOffset;
} else } else {
{
// have to merge with existing block data.. // have to merge with existing block data..
blockReq.dataLen = _blockSize; blockReq.dataLen = _blockSize;
blockReq.dataLen = cacheReadOneBlock(blockReq); blockReq.dataLen = cacheReadOneBlock(blockReq);
@ -259,8 +227,7 @@ bool BlockFileIO::write( const IORequest &req )
} }
// Finally, write the damn thing! // Finally, write the damn thing!
if(!cacheWriteOneBlock( blockReq )) if (!cacheWriteOneBlock(blockReq)) {
{
ok = false; ok = false;
break; break;
} }
@ -272,19 +239,14 @@ bool BlockFileIO::write( const IORequest &req )
partialOffset = 0; partialOffset = 0;
} }
if(mb.data) if (mb.data) MemoryPool::release(mb);
MemoryPool::release( mb );
return ok; return ok;
} }
int BlockFileIO::blockSize() const int BlockFileIO::blockSize() const { return _blockSize; }
{
return _blockSize;
}
void BlockFileIO::padFile( off_t oldSize, off_t newSize, bool forceWrite ) void BlockFileIO::padFile(off_t oldSize, off_t newSize, bool forceWrite) {
{
off_t oldLastBlock = oldSize / _blockSize; off_t oldLastBlock = oldSize / _blockSize;
off_t newLastBlock = newSize / _blockSize; off_t newLastBlock = newSize / _blockSize;
int newBlockSize = newSize % _blockSize; int newBlockSize = newSize % _blockSize;
@ -292,13 +254,11 @@ void BlockFileIO::padFile( off_t oldSize, off_t newSize, bool forceWrite )
IORequest req; IORequest req;
MemBlock mb; MemBlock mb;
if(oldLastBlock == newLastBlock) if (oldLastBlock == newLastBlock) {
{
// when the real write occurs, it will have to read in the existing // when the real write occurs, it will have to read in the existing
// data and pad it anyway, so we won't do it here (unless we're // data and pad it anyway, so we won't do it here (unless we're
// forced). // forced).
if( forceWrite ) if (forceWrite) {
{
mb = MemoryPool::allocate(_blockSize); mb = MemoryPool::allocate(_blockSize);
req.data = mb.data; req.data = mb.data;
@ -306,8 +266,7 @@ void BlockFileIO::padFile( off_t oldSize, off_t newSize, bool forceWrite )
req.dataLen = oldSize % _blockSize; req.dataLen = oldSize % _blockSize;
int outSize = newSize % _blockSize; // outSize > req.dataLen int outSize = newSize % _blockSize; // outSize > req.dataLen
if(outSize) if (outSize) {
{
memset(mb.data, 0, outSize); memset(mb.data, 0, outSize);
cacheReadOneBlock(req); cacheReadOneBlock(req);
req.dataLen = outSize; req.dataLen = outSize;
@ -315,8 +274,7 @@ void BlockFileIO::padFile( off_t oldSize, off_t newSize, bool forceWrite )
} }
} else } else
rDebug("optimization: not padding last block"); rDebug("optimization: not padding last block");
} else } else {
{
mb = MemoryPool::allocate(_blockSize); mb = MemoryPool::allocate(_blockSize);
req.data = mb.data; req.data = mb.data;
@ -328,8 +286,7 @@ void BlockFileIO::padFile( off_t oldSize, off_t newSize, bool forceWrite )
req.dataLen = oldSize % _blockSize; req.dataLen = oldSize % _blockSize;
// 1. req.dataLen == 0, iff oldSize was already a multiple of blocksize // 1. req.dataLen == 0, iff oldSize was already a multiple of blocksize
if(req.dataLen != 0) if (req.dataLen != 0) {
{
rDebug("padding block %" PRIi64, oldLastBlock); rDebug("padding block %" PRIi64, oldLastBlock);
memset(mb.data, 0, _blockSize); memset(mb.data, 0, _blockSize);
cacheReadOneBlock(req); cacheReadOneBlock(req);
@ -339,10 +296,8 @@ void BlockFileIO::padFile( off_t oldSize, off_t newSize, bool forceWrite )
} }
// 2, pad zero blocks unless holes are allowed // 2, pad zero blocks unless holes are allowed
if(!_allowHoles) if (!_allowHoles) {
{ for (; oldLastBlock != newLastBlock; ++oldLastBlock) {
for(; oldLastBlock != newLastBlock; ++oldLastBlock)
{
rDebug("padding block %" PRIi64, oldLastBlock); rDebug("padding block %" PRIi64, oldLastBlock);
req.offset = oldLastBlock * _blockSize; req.offset = oldLastBlock * _blockSize;
req.dataLen = _blockSize; req.dataLen = _blockSize;
@ -352,8 +307,7 @@ void BlockFileIO::padFile( off_t oldSize, off_t newSize, bool forceWrite )
} }
// 3. only necessary if write is forced and block is non 0 length // 3. only necessary if write is forced and block is non 0 length
if(forceWrite && newBlockSize) if (forceWrite && newBlockSize) {
{
req.offset = newLastBlock * _blockSize; req.offset = newLastBlock * _blockSize;
req.dataLen = newBlockSize; req.dataLen = newBlockSize;
memset(mb.data, 0, req.dataLen); memset(mb.data, 0, req.dataLen);
@ -361,35 +315,27 @@ void BlockFileIO::padFile( off_t oldSize, off_t newSize, bool forceWrite )
} }
} }
if(mb.data) if (mb.data) MemoryPool::release(mb);
MemoryPool::release( mb );
} }
int BlockFileIO::truncateBase( off_t size, FileIO *base ) int BlockFileIO::truncateBase(off_t size, FileIO *base) {
{
int partialBlock = size % _blockSize; int partialBlock = size % _blockSize;
int res = 0; int res = 0;
off_t oldSize = getSize(); off_t oldSize = getSize();
if( size > oldSize ) if (size > oldSize) {
{
// truncate can be used to extend a file as well. truncate man page // truncate can be used to extend a file as well. truncate man page
// states that it will pad with 0's. // states that it will pad with 0's.
// do the truncate so that the underlying filesystem can allocate // do the truncate so that the underlying filesystem can allocate
// the space, and then we'll fill it in padFile.. // the space, and then we'll fill it in padFile..
if(base) if (base) base->truncate(size);
base->truncate( size );
const bool forceWrite = true; const bool forceWrite = true;
padFile(oldSize, size, forceWrite); padFile(oldSize, size, forceWrite);
} else } else if (size == oldSize) {
if( size == oldSize )
{
// the easiest case, but least likely.... // the easiest case, but least likely....
} else } else if (partialBlock) {
if( partialBlock )
{
// partial block after truncate. Need to read in the block being // partial block after truncate. Need to read in the block being
// truncated before the truncate. Then write it back out afterwards, // truncated before the truncate. Then write it back out afterwards,
// since the encoding will change.. // since the encoding will change..
@ -404,29 +350,24 @@ int BlockFileIO::truncateBase( off_t size, FileIO *base )
ssize_t rdSz = cacheReadOneBlock(req); ssize_t rdSz = cacheReadOneBlock(req);
// do the truncate // do the truncate
if(base) if (base) res = base->truncate(size);
res = base->truncate( size );
// write back out partial block // write back out partial block
req.dataLen = partialBlock; req.dataLen = partialBlock;
bool wrRes = cacheWriteOneBlock(req); bool wrRes = cacheWriteOneBlock(req);
if((rdSz < 0) || (!wrRes)) if ((rdSz < 0) || (!wrRes)) {
{
// rwarning - unlikely to ever occur.. // rwarning - unlikely to ever occur..
rWarning(_("truncate failure: read %i bytes, partial block of %i"), rWarning(_("truncate failure: read %i bytes, partial block of %i"),
(int)rdSz, partialBlock); (int)rdSz, partialBlock);
} }
MemoryPool::release(mb); MemoryPool::release(mb);
} else } else {
{
// truncating on a block bounday. No need to re-encode the last // truncating on a block bounday. No need to re-encode the last
// block.. // block..
if(base) if (base) res = base->truncate(size);
res = base->truncate( size );
} }
return res; return res;
} }

View File

@ -32,8 +32,7 @@
the existing block, merge with the write request, and a write of the full the existing block, merge with the write request, and a write of the full
block. block.
*/ */
class BlockFileIO : public FileIO class BlockFileIO : public FileIO {
{
public: public:
BlockFileIO(int blockSize, const FSConfigPtr &cfg); BlockFileIO(int blockSize, const FSConfigPtr &cfg);
virtual ~BlockFileIO(); virtual ~BlockFileIO();
@ -45,7 +44,6 @@ public:
virtual int blockSize() const; virtual int blockSize() const;
protected: protected:
int truncateBase(off_t size, FileIO *base); int truncateBase(off_t size, FileIO *base);
void padFile(off_t oldSize, off_t newSize, bool forceWrite); void padFile(off_t oldSize, off_t newSize, bool forceWrite);
@ -65,4 +63,3 @@ protected:
}; };
#endif #endif

View File

@ -35,42 +35,40 @@ using namespace rel;
static RLogChannel *Info = DEF_CHANNEL("info/nameio", Log_Info); static RLogChannel *Info = DEF_CHANNEL("info/nameio", Log_Info);
static shared_ptr<NameIO> NewBlockNameIO(const Interface &iface, static shared_ptr<NameIO> NewBlockNameIO(const Interface &iface,
const shared_ptr<Cipher> &cipher, const CipherKey &key ) const shared_ptr<Cipher> &cipher,
{ const CipherKey &key) {
int blockSize = 8; int blockSize = 8;
if(cipher) if (cipher) blockSize = cipher->cipherBlockSize();
blockSize = cipher->cipherBlockSize();
return shared_ptr<NameIO>( return shared_ptr<NameIO>(
new BlockNameIO(iface, cipher, key, blockSize, false)); new BlockNameIO(iface, cipher, key, blockSize, false));
} }
static shared_ptr<NameIO> NewBlockNameIO32(const Interface &iface, static shared_ptr<NameIO> NewBlockNameIO32(const Interface &iface,
const shared_ptr<Cipher> &cipher, const CipherKey &key ) const shared_ptr<Cipher> &cipher,
{ const CipherKey &key) {
int blockSize = 8; int blockSize = 8;
if(cipher) if (cipher) blockSize = cipher->cipherBlockSize();
blockSize = cipher->cipherBlockSize();
return shared_ptr<NameIO>( return shared_ptr<NameIO>(
new BlockNameIO(iface, cipher, key, blockSize, true)); new BlockNameIO(iface, cipher, key, blockSize, true));
} }
static bool BlockIO_registered = NameIO::Register("Block", static bool BlockIO_registered = NameIO::Register(
"Block",
// description of block name encoding algorithm.. // description of block name encoding algorithm..
// xgroup(setup) // xgroup(setup)
gettext_noop("Block encoding, hides file name size somewhat"), gettext_noop("Block encoding, hides file name size somewhat"),
BlockNameIO::CurrentInterface(false), BlockNameIO::CurrentInterface(false), NewBlockNameIO);
NewBlockNameIO);
static bool BlockIO32_registered = NameIO::Register("Block32", static bool BlockIO32_registered = NameIO::Register(
"Block32",
// description of block name encoding algorithm.. // description of block name encoding algorithm..
// xgroup(setup) // xgroup(setup)
gettext_noop("Block encoding with base32 output for case-sensitive systems"), gettext_noop(
BlockNameIO::CurrentInterface(true), "Block encoding with base32 output for case-sensitive systems"),
NewBlockNameIO32); BlockNameIO::CurrentInterface(true), NewBlockNameIO32);
/* /*
- Version 1.0 computed MAC over the filename, but not the padding bytes. - Version 1.0 computed MAC over the filename, but not the padding bytes.
@ -89,8 +87,7 @@ static bool BlockIO32_registered = NameIO::Register("Block32",
- Version 4.0 adds support for base32, creating names more suitable for - Version 4.0 adds support for base32, creating names more suitable for
case-insensitive filesystems (eg Mac). case-insensitive filesystems (eg Mac).
*/ */
Interface BlockNameIO::CurrentInterface(bool caseSensitive) Interface BlockNameIO::CurrentInterface(bool caseSensitive) {
{
// implement major version 4 plus support for two prior versions // implement major version 4 plus support for two prior versions
if (caseSensitive) if (caseSensitive)
return Interface("nameio/block32", 4, 0, 2); return Interface("nameio/block32", 4, 0, 2);
@ -99,30 +96,24 @@ Interface BlockNameIO::CurrentInterface(bool caseSensitive)
} }
BlockNameIO::BlockNameIO(const rel::Interface &iface, BlockNameIO::BlockNameIO(const rel::Interface &iface,
const shared_ptr<Cipher> &cipher, const shared_ptr<Cipher> &cipher, const CipherKey &key,
const CipherKey &key, int blockSize, int blockSize, bool caseSensitiveEncoding)
bool caseSensitiveEncoding ) : _interface(iface.current()),
: _interface( iface.current() ) _bs(blockSize),
, _bs( blockSize ) _cipher(cipher),
, _cipher( cipher ) _key(key),
, _key( key ) _caseSensitive(caseSensitiveEncoding) {
, _caseSensitive( caseSensitiveEncoding )
{
// just to be safe.. // just to be safe..
rAssert(blockSize < 128); rAssert(blockSize < 128);
} }
BlockNameIO::~BlockNameIO() BlockNameIO::~BlockNameIO() {}
{
}
Interface BlockNameIO::interface() const Interface BlockNameIO::interface() const {
{
return CurrentInterface(_caseSensitive); return CurrentInterface(_caseSensitive);
} }
int BlockNameIO::maxEncodedNameLen( int plaintextNameLen ) const int BlockNameIO::maxEncodedNameLen(int plaintextNameLen) const {
{
// number of blocks, rounded up.. Only an estimate at this point, err on // number of blocks, rounded up.. Only an estimate at this point, err on
// the size of too much space rather then too little. // the size of too much space rather then too little.
int numBlocks = (plaintextNameLen + _bs) / _bs; int numBlocks = (plaintextNameLen + _bs) / _bs;
@ -133,31 +124,26 @@ int BlockNameIO::maxEncodedNameLen( int plaintextNameLen ) const
return B256ToB64Bytes(encodedNameLen); return B256ToB64Bytes(encodedNameLen);
} }
int BlockNameIO::maxDecodedNameLen( int encodedNameLen ) const int BlockNameIO::maxDecodedNameLen(int encodedNameLen) const {
{ int decLen256 = _caseSensitive ? B32ToB256Bytes(encodedNameLen)
int decLen256 = _caseSensitive ? : B64ToB256Bytes(encodedNameLen);
B32ToB256Bytes( encodedNameLen ) :
B64ToB256Bytes( encodedNameLen );
return decLen256 - 2; // 2 checksum bytes removed.. return decLen256 - 2; // 2 checksum bytes removed..
} }
int BlockNameIO::encodeName( const char *plaintextName, int length, int BlockNameIO::encodeName(const char *plaintextName, int length, uint64_t *iv,
uint64_t *iv, char *encodedName ) const char *encodedName) const {
{
// copy the data into the encoding buffer.. // copy the data into the encoding buffer..
memcpy(encodedName + 2, plaintextName, length); memcpy(encodedName + 2, plaintextName, length);
// Pad encryption buffer to block boundary.. // Pad encryption buffer to block boundary..
int padding = _bs - length % _bs; int padding = _bs - length % _bs;
if(padding == 0) if (padding == 0) padding = _bs; // padding a full extra block!
padding = _bs; // padding a full extra block!
memset(encodedName + length + 2, (unsigned char)padding, padding); memset(encodedName + length + 2, (unsigned char)padding, padding);
// store the IV before it is modified by the MAC call. // store the IV before it is modified by the MAC call.
uint64_t tmpIV = 0; uint64_t tmpIV = 0;
if( iv && _interface >= 3 ) if (iv && _interface >= 3) tmpIV = *iv;
tmpIV = *iv;
// include padding in MAC computation // include padding in MAC computation
unsigned int mac = _cipher->MAC_16((unsigned char *)encodedName + 2, unsigned int mac = _cipher->MAC_16((unsigned char *)encodedName + 2,
@ -174,57 +160,49 @@ int BlockNameIO::encodeName( const char *plaintextName, int length,
int encodedStreamLen = length + 2 + padding; int encodedStreamLen = length + 2 + padding;
int encLen; int encLen;
if (_caseSensitive) if (_caseSensitive) {
{
encLen = B256ToB32Bytes(encodedStreamLen); encLen = B256ToB32Bytes(encodedStreamLen);
changeBase2Inline( (unsigned char *)encodedName, encodedStreamLen, changeBase2Inline((unsigned char *)encodedName, encodedStreamLen, 8, 5,
8, 5, true ); true);
B32ToAscii((unsigned char *)encodedName, encLen); B32ToAscii((unsigned char *)encodedName, encLen);
} else } else {
{
encLen = B256ToB64Bytes(encodedStreamLen); encLen = B256ToB64Bytes(encodedStreamLen);
changeBase2Inline( (unsigned char *)encodedName, encodedStreamLen, changeBase2Inline((unsigned char *)encodedName, encodedStreamLen, 8, 6,
8, 6, true ); true);
B64ToAscii((unsigned char *)encodedName, encLen); B64ToAscii((unsigned char *)encodedName, encLen);
} }
return encLen; return encLen;
} }
int BlockNameIO::decodeName( const char *encodedName, int length, int BlockNameIO::decodeName(const char *encodedName, int length, uint64_t *iv,
uint64_t *iv, char *plaintextName ) const char *plaintextName) const {
{ int decLen256 =
int decLen256 = _caseSensitive ? _caseSensitive ? B32ToB256Bytes(length) : B64ToB256Bytes(length);
B32ToB256Bytes( length ) :
B64ToB256Bytes( length );
int decodedStreamLen = decLen256 - 2; int decodedStreamLen = decLen256 - 2;
// don't bother trying to decode files which are too small // don't bother trying to decode files which are too small
if(decodedStreamLen < _bs) if (decodedStreamLen < _bs) throw ERROR("Filename too small to decode");
throw ERROR("Filename too small to decode");
BUFFER_INIT(tmpBuf, 32, (unsigned int)length); BUFFER_INIT(tmpBuf, 32, (unsigned int)length);
// decode into tmpBuf, // decode into tmpBuf,
if (_caseSensitive) if (_caseSensitive) {
{
AsciiToB32((unsigned char *)tmpBuf, (unsigned char *)encodedName, length); AsciiToB32((unsigned char *)tmpBuf, (unsigned char *)encodedName, length);
changeBase2Inline((unsigned char *)tmpBuf, length, 5, 8, false); changeBase2Inline((unsigned char *)tmpBuf, length, 5, 8, false);
} else } else {
{
AsciiToB64((unsigned char *)tmpBuf, (unsigned char *)encodedName, length); AsciiToB64((unsigned char *)tmpBuf, (unsigned char *)encodedName, length);
changeBase2Inline((unsigned char *)tmpBuf, length, 6, 8, false); changeBase2Inline((unsigned char *)tmpBuf, length, 6, 8, false);
} }
// pull out the header information // pull out the header information
unsigned int mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8 unsigned int mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8 |
| ((unsigned int)((unsigned char)tmpBuf[1])); ((unsigned int)((unsigned char)tmpBuf[1]));
uint64_t tmpIV = 0; uint64_t tmpIV = 0;
if( iv && _interface >= 3 ) if (iv && _interface >= 3) tmpIV = *iv;
tmpIV = *iv;
_cipher->blockDecode((unsigned char *)tmpBuf + 2, decodedStreamLen, _cipher->blockDecode((unsigned char *)tmpBuf + 2, decodedStreamLen,
(uint64_t)mac ^ tmpIV, _key); (uint64_t)mac ^ tmpIV, _key);
@ -234,10 +212,8 @@ int BlockNameIO::decodeName( const char *encodedName, int length,
int finalSize = decodedStreamLen - padding; int finalSize = decodedStreamLen - padding;
// might happen if there is an error decoding.. // might happen if there is an error decoding..
if(padding > _bs || finalSize < 0) if (padding > _bs || finalSize < 0) {
{ rDebug("padding, _bx, finalSize = %i, %i, %i", padding, _bs, finalSize);
rDebug("padding, _bx, finalSize = %i, %i, %i", padding,
_bs, finalSize);
throw ERROR("invalid padding size"); throw ERROR("invalid padding size");
} }
@ -251,8 +227,7 @@ int BlockNameIO::decodeName( const char *encodedName, int length,
BUFFER_RESET(tmpBuf); BUFFER_RESET(tmpBuf);
if(mac2 != mac) if (mac2 != mac) {
{
rDebug("checksum mismatch: expected %u, got %u", mac, mac2); rDebug("checksum mismatch: expected %u, got %u", mac, mac2);
rDebug("on decode of %i bytes", finalSize); rDebug("on decode of %i bytes", finalSize);
throw ERROR("checksum mismatch in filename decode"); throw ERROR("checksum mismatch in filename decode");
@ -261,8 +236,4 @@ int BlockNameIO::decodeName( const char *encodedName, int length,
return finalSize; return finalSize;
} }
bool BlockNameIO::Enabled() bool BlockNameIO::Enabled() { return true; }
{
return true;
}

View File

@ -32,13 +32,11 @@ class Cipher;
mode to encode filenames. The filenames are padded to be a multiple of the mode to encode filenames. The filenames are padded to be a multiple of the
cipher block size. cipher block size.
*/ */
class BlockNameIO : public NameIO class BlockNameIO : public NameIO {
{
public: public:
static rel::Interface CurrentInterface(bool caseSensitive = false); static rel::Interface CurrentInterface(bool caseSensitive = false);
BlockNameIO( const rel::Interface &iface, BlockNameIO(const rel::Interface &iface, const shared_ptr<Cipher> &cipher,
const shared_ptr<Cipher> &cipher,
const CipherKey &key, int blockSize, const CipherKey &key, int blockSize,
bool caseSensitiveEncoding = false); bool caseSensitiveEncoding = false);
virtual ~BlockNameIO(); virtual ~BlockNameIO();
@ -50,11 +48,12 @@ public:
// hack to help with static builds // hack to help with static builds
static bool Enabled(); static bool Enabled();
protected: protected:
virtual int encodeName( const char *plaintextName, int length, virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
uint64_t *iv, char *encodedName ) const; char *encodedName) const;
virtual int decodeName( const char *encodedName, int length, virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
uint64_t *iv, char *plaintextName ) const; char *plaintextName) const;
private: private:
int _interface; int _interface;
@ -64,6 +63,4 @@ private:
bool _caseSensitive; bool _caseSensitive;
}; };
#endif #endif

View File

@ -39,19 +39,14 @@ using namespace std;
using namespace rel; using namespace rel;
#define REF_MODULE(TYPE) \ #define REF_MODULE(TYPE) \
if( !TYPE::Enabled() ) \ if (!TYPE::Enabled()) cerr << "referenceModule: should never happen\n";
cerr << "referenceModule: should never happen\n";
static static void AddSymbolReferences() {
void AddSymbolReferences()
{
REF_MODULE(SSL_Cipher) REF_MODULE(SSL_Cipher)
REF_MODULE(NullCipher) REF_MODULE(NullCipher)
} }
struct CipherAlg {
struct CipherAlg
{
bool hidden; bool hidden;
Cipher::CipherConstructor constructor; Cipher::CipherConstructor constructor;
string description; string description;
@ -63,22 +58,18 @@ struct CipherAlg
typedef multimap<string, CipherAlg> CipherMap_t; typedef multimap<string, CipherAlg> CipherMap_t;
static CipherMap_t *gCipherMap = NULL; static CipherMap_t *gCipherMap = NULL;
std::list<Cipher::CipherAlgorithm> std::list<Cipher::CipherAlgorithm> Cipher::GetAlgorithmList(
Cipher::GetAlgorithmList( bool includeHidden ) bool includeHidden) {
{
AddSymbolReferences(); AddSymbolReferences();
list<CipherAlgorithm> result; list<CipherAlgorithm> result;
if(!gCipherMap) if (!gCipherMap) return result;
return result;
CipherMap_t::const_iterator it; CipherMap_t::const_iterator it;
CipherMap_t::const_iterator mapEnd = gCipherMap->end(); CipherMap_t::const_iterator mapEnd = gCipherMap->end();
for(it = gCipherMap->begin(); it != mapEnd; ++it) for (it = gCipherMap->begin(); it != mapEnd; ++it) {
{ if (includeHidden || !it->second.hidden) {
if(includeHidden || !it->second.hidden)
{
CipherAlgorithm tmp; CipherAlgorithm tmp;
tmp.name = it->first; tmp.name = it->first;
tmp.description = it->second.description; tmp.description = it->second.description;
@ -94,21 +85,19 @@ Cipher::GetAlgorithmList( bool includeHidden )
} }
bool Cipher::Register(const char *name, const char *description, bool Cipher::Register(const char *name, const char *description,
const Interface &iface, CipherConstructor fn, bool hidden) const Interface &iface, CipherConstructor fn,
{ bool hidden) {
Range keyLength(-1, -1, 1); Range keyLength(-1, -1, 1);
Range blockSize(-1, -1, 1); Range blockSize(-1, -1, 1);
return Cipher::Register( name, description, iface, return Cipher::Register(name, description, iface, keyLength, blockSize, fn,
keyLength, blockSize, fn, hidden ); hidden);
} }
bool Cipher::Register(const char *name, const char *description, bool Cipher::Register(const char *name, const char *description,
const Interface &iface, const Range &keyLength, const Interface &iface, const Range &keyLength,
const Range &blockSize, const Range &blockSize, CipherConstructor fn,
CipherConstructor fn, bool hidden) bool hidden) {
{ if (!gCipherMap) gCipherMap = new CipherMap_t;
if(!gCipherMap)
gCipherMap = new CipherMap_t;
CipherAlg ca; CipherAlg ca;
ca.hidden = hidden; ca.hidden = hidden;
@ -122,15 +111,12 @@ bool Cipher::Register(const char *name, const char *description,
return true; return true;
} }
shared_ptr<Cipher> Cipher::New(const string &name, int keyLen) shared_ptr<Cipher> Cipher::New(const string &name, int keyLen) {
{
shared_ptr<Cipher> result; shared_ptr<Cipher> result;
if(gCipherMap) if (gCipherMap) {
{
CipherMap_t::const_iterator it = gCipherMap->find(name); CipherMap_t::const_iterator it = gCipherMap->find(name);
if(it != gCipherMap->end()) if (it != gCipherMap->end()) {
{
CipherConstructor fn = it->second.constructor; CipherConstructor fn = it->second.constructor;
// use current interface.. // use current interface..
result = (*fn)(it->second.iface, keyLen); result = (*fn)(it->second.iface, keyLen);
@ -140,19 +126,15 @@ shared_ptr<Cipher> Cipher::New(const string &name, int keyLen)
return result; return result;
} }
shared_ptr<Cipher> Cipher::New( const Interface &iface, int keyLen ) shared_ptr<Cipher> Cipher::New(const Interface &iface, int keyLen) {
{
shared_ptr<Cipher> result; shared_ptr<Cipher> result;
if(gCipherMap) if (gCipherMap) {
{
CipherMap_t::const_iterator it; CipherMap_t::const_iterator it;
CipherMap_t::const_iterator mapEnd = gCipherMap->end(); CipherMap_t::const_iterator mapEnd = gCipherMap->end();
for(it = gCipherMap->begin(); it != mapEnd; ++it) for (it = gCipherMap->begin(); it != mapEnd; ++it) {
{
// TODO: we should look for the newest implementation.. // TODO: we should look for the newest implementation..
if( it->second.iface.implements( iface ) ) if (it->second.iface.implements(iface)) {
{
CipherConstructor fn = it->second.constructor; CipherConstructor fn = it->second.constructor;
// pass in requested interface.. // pass in requested interface..
result = (*fn)(iface, keyLen); result = (*fn)(iface, keyLen);
@ -167,17 +149,12 @@ shared_ptr<Cipher> Cipher::New( const Interface &iface, int keyLen )
return result; return result;
} }
Cipher::Cipher() Cipher::Cipher() {}
{
}
Cipher::~Cipher() Cipher::~Cipher() {}
{
}
unsigned int Cipher::MAC_32(const unsigned char *src, int len, unsigned int Cipher::MAC_32(const unsigned char *src, int len,
const CipherKey &key, uint64_t *chainedIV ) const const CipherKey &key, uint64_t *chainedIV) const {
{
uint64_t mac64 = MAC_64(src, len, key, chainedIV); uint64_t mac64 = MAC_64(src, len, key, chainedIV);
unsigned int mac32 = ((mac64 >> 32) & 0xffffffff) ^ (mac64 & 0xffffffff); unsigned int mac32 = ((mac64 >> 32) & 0xffffffff) ^ (mac64 & 0xffffffff);
@ -186,8 +163,7 @@ unsigned int Cipher::MAC_32( const unsigned char *src, int len,
} }
unsigned int Cipher::MAC_16(const unsigned char *src, int len, unsigned int Cipher::MAC_16(const unsigned char *src, int len,
const CipherKey &key, uint64_t *chainedIV ) const const CipherKey &key, uint64_t *chainedIV) const {
{
uint64_t mac64 = MAC_64(src, len, key, chainedIV); uint64_t mac64 = MAC_64(src, len, key, chainedIV);
unsigned int mac32 = ((mac64 >> 32) & 0xffffffff) ^ (mac64 & 0xffffffff); unsigned int mac32 = ((mac64 >> 32) & 0xffffffff) ^ (mac64 & 0xffffffff);
@ -196,21 +172,18 @@ unsigned int Cipher::MAC_16( const unsigned char *src, int len,
return mac16; return mac16;
} }
bool Cipher::nameEncode( unsigned char *data, int len, bool Cipher::nameEncode(unsigned char *data, int len, uint64_t iv64,
uint64_t iv64, const CipherKey &key ) const const CipherKey &key) const {
{
return streamEncode(data, len, iv64, key); return streamEncode(data, len, iv64, key);
} }
bool Cipher::nameDecode( unsigned char *data, int len, bool Cipher::nameDecode(unsigned char *data, int len, uint64_t iv64,
uint64_t iv64, const CipherKey &key ) const const CipherKey &key) const {
{
return streamDecode(data, len, iv64, key); return streamDecode(data, len, iv64, key);
} }
string Cipher::encodeAsString(const CipherKey &key, string Cipher::encodeAsString(const CipherKey &key,
const CipherKey &encodingKey ) const CipherKey &encodingKey) {
{
int encodedKeySize = this->encodedKeySize(); int encodedKeySize = this->encodedKeySize();
unsigned char *keyBuf = new unsigned char[encodedKeySize]; unsigned char *keyBuf = new unsigned char[encodedKeySize];

View File

@ -37,16 +37,14 @@
Cipher's should register themselves so they can be instanciated via Cipher's should register themselves so they can be instanciated via
Cipher::New(). Cipher::New().
*/ */
class Cipher class Cipher {
{
public: public:
// if no key length was indicated when cipher was registered, then keyLen // if no key length was indicated when cipher was registered, then keyLen
// <= 0 will be used. // <= 0 will be used.
typedef shared_ptr<Cipher>(*CipherConstructor)(const rel::Interface &iface, typedef shared_ptr<Cipher>(*CipherConstructor)(const rel::Interface &iface,
int keyLenBits); int keyLenBits);
struct CipherAlgorithm struct CipherAlgorithm {
{
std::string name; std::string name;
std::string description; std::string description;
rel::Interface iface; rel::Interface iface;
@ -54,29 +52,19 @@ public:
Range blockSize; Range blockSize;
}; };
typedef std::list<CipherAlgorithm> AlgorithmList; typedef std::list<CipherAlgorithm> AlgorithmList;
static AlgorithmList GetAlgorithmList(bool includeHidden = false); static AlgorithmList GetAlgorithmList(bool includeHidden = false);
static shared_ptr<Cipher> New(const rel::Interface &iface, int keyLen = -1);
static shared_ptr<Cipher> New(const std::string &cipherName, int keyLen = -1);
static shared_ptr<Cipher> New( const rel::Interface &iface, static bool Register(const char *cipherName, const char *description,
int keyLen = -1);
static shared_ptr<Cipher> New( const std::string &cipherName,
int keyLen = -1 );
static bool Register(const char *cipherName,
const char *description,
const rel::Interface &iface, const rel::Interface &iface,
CipherConstructor constructor, CipherConstructor constructor, bool hidden = false);
static bool Register(const char *cipherName, const char *description,
const rel::Interface &iface, const Range &keyLength,
const Range &blockSize, CipherConstructor constructor,
bool hidden = false); bool hidden = false);
static bool Register(const char *cipherName,
const char *description,
const rel::Interface &iface,
const Range &keyLength, const Range &blockSize,
CipherConstructor constructor,
bool hidden = false);
Cipher(); Cipher();
virtual ~Cipher(); virtual ~Cipher();
@ -123,21 +111,22 @@ public:
// 64 bit MAC of the data with the given key // 64 bit MAC of the data with the given key
virtual uint64_t MAC_64(const unsigned char *src, int len, virtual uint64_t MAC_64(const unsigned char *src, int len,
const CipherKey &key, uint64_t *chainedIV = 0 ) const =0; const CipherKey &key,
uint64_t *chainedIV = 0) const = 0;
// based on reductions of MAC_64 // based on reductions of MAC_64
unsigned int MAC_32( const unsigned char *src, int len, unsigned int MAC_32(const unsigned char *src, int len, const CipherKey &key,
const CipherKey &key, uint64_t *chainedIV = 0 ) const; uint64_t *chainedIV = 0) const;
unsigned int MAC_16( const unsigned char *src, int len, unsigned int MAC_16(const unsigned char *src, int len, const CipherKey &key,
const CipherKey &key, uint64_t *chainedIV = 0 ) const; uint64_t *chainedIV = 0) const;
// functional interfaces // functional interfaces
/* /*
Stream encoding of data in-place. The stream data can be any length. Stream encoding of data in-place. The stream data can be any length.
*/ */
virtual bool streamEncode( unsigned char *data, int len, virtual bool streamEncode(unsigned char *data, int len, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const=0; const CipherKey &key) const = 0;
virtual bool streamDecode( unsigned char *data, int len, virtual bool streamDecode(unsigned char *data, int len, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const=0; const CipherKey &key) const = 0;
/* /*
These are just aliases of streamEncode / streamDecode, but there are These are just aliases of streamEncode / streamDecode, but there are
@ -145,21 +134,19 @@ public:
effectively two stream modes - one for encoding partial blocks and effectively two stream modes - one for encoding partial blocks and
another for encoding filenames. another for encoding filenames.
*/ */
virtual bool nameEncode( unsigned char *data, int len, virtual bool nameEncode(unsigned char *data, int len, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const; const CipherKey &key) const;
virtual bool nameDecode( unsigned char *data, int len, virtual bool nameDecode(unsigned char *data, int len, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const; const CipherKey &key) const;
/* /*
Block encoding of data in-place. The data size should be a multiple of Block encoding of data in-place. The data size should be a multiple of
the cipher block size. the cipher block size.
*/ */
virtual bool blockEncode(unsigned char *buf, int size, virtual bool blockEncode(unsigned char *buf, int size, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const=0; const CipherKey &key) const = 0;
virtual bool blockDecode(unsigned char *buf, int size, virtual bool blockDecode(unsigned char *buf, int size, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const=0; const CipherKey &key) const = 0;
}; };
#endif #endif

View File

@ -39,11 +39,9 @@ static rel::Interface CipherFileIO_iface("FileIO/Cipher", 2, 0, 1);
const int HEADER_SIZE = 8; // 64 bit initialization vector.. const int HEADER_SIZE = 8; // 64 bit initialization vector..
static bool checkSize( int fsBlockSize, int cipherBlockSize ) static bool checkSize(int fsBlockSize, int cipherBlockSize) {
{
int blockBoundary = fsBlockSize % cipherBlockSize; int blockBoundary = fsBlockSize % cipherBlockSize;
if(blockBoundary != 0) if (blockBoundary != 0) {
{
rError("CipherFileIO: blocks should be multiple of cipher block size"); rError("CipherFileIO: blocks should be multiple of cipher block size");
return true; return true;
} else } else
@ -52,13 +50,12 @@ static bool checkSize( int fsBlockSize, int cipherBlockSize )
CipherFileIO::CipherFileIO(const shared_ptr<FileIO> &_base, CipherFileIO::CipherFileIO(const shared_ptr<FileIO> &_base,
const FSConfigPtr &cfg) const FSConfigPtr &cfg)
: BlockFileIO( cfg->config->blockSize, cfg ) : BlockFileIO(cfg->config->blockSize, cfg),
, base( _base ) base(_base),
, haveHeader( cfg->config->uniqueIV ) haveHeader(cfg->config->uniqueIV),
, externalIV( 0 ) externalIV(0),
, fileIV( 0 ) fileIV(0),
, lastFlags( 0 ) lastFlags(0) {
{
fsConfig = cfg; fsConfig = cfg;
cipher = cfg->cipher; cipher = cfg->cipher;
key = cfg->key; key = cfg->key;
@ -70,67 +67,49 @@ CipherFileIO::CipherFileIO( const shared_ptr<FileIO> &_base,
fsConfig->cipher->cipherBlockSize()); fsConfig->cipher->cipherBlockSize());
} }
CipherFileIO::~CipherFileIO() CipherFileIO::~CipherFileIO() {}
{
}
rel::Interface CipherFileIO::interface() const rel::Interface CipherFileIO::interface() const { return CipherFileIO_iface; }
{
return CipherFileIO_iface;
}
int CipherFileIO::open( int flags ) int CipherFileIO::open(int flags) {
{
int res = base->open(flags); int res = base->open(flags);
if( res >= 0 ) if (res >= 0) lastFlags = flags;
lastFlags = flags;
return res; return res;
} }
void CipherFileIO::setFileName( const char *fileName ) void CipherFileIO::setFileName(const char *fileName) {
{
base->setFileName(fileName); base->setFileName(fileName);
} }
const char *CipherFileIO::getFileName() const const char *CipherFileIO::getFileName() const { return base->getFileName(); }
{
return base->getFileName();
}
bool CipherFileIO::setIV( uint64_t iv ) bool CipherFileIO::setIV(uint64_t iv) {
{
rDebug("in setIV, current IV = %" PRIu64 ", new IV = %" PRIu64 rDebug("in setIV, current IV = %" PRIu64 ", new IV = %" PRIu64
", fileIV = %" PRIu64, ", fileIV = %" PRIu64,
externalIV, iv, fileIV); externalIV, iv, fileIV);
if(externalIV == 0) if (externalIV == 0) {
{
// we're just being told about which IV to use. since we haven't // we're just being told about which IV to use. since we haven't
// initialized the fileIV, there is no need to just yet.. // initialized the fileIV, there is no need to just yet..
externalIV = iv; externalIV = iv;
if (fileIV != 0) if (fileIV != 0)
rWarning("fileIV initialized before externalIV! (%" PRIu64 rWarning("fileIV initialized before externalIV! (%" PRIu64 ", %" PRIu64
", %" PRIu64 ")", fileIV, externalIV); ")",
} else fileIV, externalIV);
if(haveHeader) } else if (haveHeader) {
{
// we have an old IV, and now a new IV, so we need to update the fileIV // we have an old IV, and now a new IV, so we need to update the fileIV
// on disk. // on disk.
if(fileIV == 0) if (fileIV == 0) {
{
// ensure the file is open for read/write.. // ensure the file is open for read/write..
int newFlags = lastFlags | O_RDWR; int newFlags = lastFlags | O_RDWR;
int res = base->open(newFlags); int res = base->open(newFlags);
if(res < 0) if (res < 0) {
{ if (res == -EISDIR) {
if(res == -EISDIR)
{
// duh -- there are no file headers for directories! // duh -- there are no file headers for directories!
externalIV = iv; externalIV = iv;
return base->setIV(iv); return base->setIV(iv);
} else } else {
{
rDebug("writeHeader failed to re-open for write"); rDebug("writeHeader failed to re-open for write");
return false; return false;
} }
@ -140,8 +119,7 @@ bool CipherFileIO::setIV( uint64_t iv )
uint64_t oldIV = externalIV; uint64_t oldIV = externalIV;
externalIV = iv; externalIV = iv;
if(!writeHeader()) if (!writeHeader()) {
{
externalIV = oldIV; externalIV = oldIV;
return false; return false;
} }
@ -150,13 +128,11 @@ bool CipherFileIO::setIV( uint64_t iv )
return base->setIV(iv); return base->setIV(iv);
} }
int CipherFileIO::getAttr( struct stat *stbuf ) const int CipherFileIO::getAttr(struct stat *stbuf) const {
{
int res = base->getAttr(stbuf); int res = base->getAttr(stbuf);
// adjust size if we have a file header // adjust size if we have a file header
if((res == 0) && haveHeader && if ((res == 0) && haveHeader && S_ISREG(stbuf->st_mode) &&
S_ISREG(stbuf->st_mode) && (stbuf->st_size > 0)) (stbuf->st_size > 0)) {
{
rAssert(stbuf->st_size >= HEADER_SIZE); rAssert(stbuf->st_size >= HEADER_SIZE);
stbuf->st_size -= HEADER_SIZE; stbuf->st_size -= HEADER_SIZE;
} }
@ -164,26 +140,22 @@ int CipherFileIO::getAttr( struct stat *stbuf ) const
return res; return res;
} }
off_t CipherFileIO::getSize() const off_t CipherFileIO::getSize() const {
{
off_t size = base->getSize(); off_t size = base->getSize();
// No check on S_ISREG here -- don't call getSize over getAttr unless this // No check on S_ISREG here -- don't call getSize over getAttr unless this
// is a normal file! // is a normal file!
if(haveHeader && size > 0) if (haveHeader && size > 0) {
{
rAssert(size >= HEADER_SIZE); rAssert(size >= HEADER_SIZE);
size -= HEADER_SIZE; size -= HEADER_SIZE;
} }
return size; return size;
} }
void CipherFileIO::initHeader( ) void CipherFileIO::initHeader() {
{
// check if the file has a header, and read it if it does.. Otherwise, // check if the file has a header, and read it if it does.. Otherwise,
// create one. // create one.
off_t rawSize = base->getSize(); off_t rawSize = base->getSize();
if(rawSize >= HEADER_SIZE) if (rawSize >= HEADER_SIZE) {
{
rDebug("reading existing header, rawSize = %" PRIi64, rawSize); rDebug("reading existing header, rawSize = %" PRIi64, rawSize);
// has a header.. read it // has a header.. read it
unsigned char buf[8] = {0}; unsigned char buf[8] = {0};
@ -194,34 +166,28 @@ void CipherFileIO::initHeader( )
req.dataLen = 8; req.dataLen = 8;
base->read(req); base->read(req);
cipher->streamDecode( buf, sizeof(buf), cipher->streamDecode(buf, sizeof(buf), externalIV, key);
externalIV, key );
fileIV = 0; fileIV = 0;
for(int i=0; i<8; ++i) for (int i = 0; i < 8; ++i) fileIV = (fileIV << 8) | (uint64_t)buf[i];
fileIV = (fileIV << 8) | (uint64_t)buf[i];
rAssert(fileIV != 0); // 0 is never used.. rAssert(fileIV != 0); // 0 is never used..
} else } else {
{
rDebug("creating new file IV header"); rDebug("creating new file IV header");
unsigned char buf[8] = {0}; unsigned char buf[8] = {0};
do do {
{
if (!cipher->randomize(buf, 8, false)) if (!cipher->randomize(buf, 8, false))
throw ERROR("Unable to generate a random file IV"); throw ERROR("Unable to generate a random file IV");
fileIV = 0; fileIV = 0;
for(int i=0; i<8; ++i) for (int i = 0; i < 8; ++i) fileIV = (fileIV << 8) | (uint64_t)buf[i];
fileIV = (fileIV << 8) | (uint64_t)buf[i];
if (fileIV == 0) if (fileIV == 0)
rWarning("Unexpected result: randomize returned 8 null bytes!"); rWarning("Unexpected result: randomize returned 8 null bytes!");
} while (fileIV == 0); // don't accept 0 as an option.. } while (fileIV == 0); // don't accept 0 as an option..
if( base->isWritable() ) if (base->isWritable()) {
{
cipher->streamEncode(buf, sizeof(buf), externalIV, key); cipher->streamEncode(buf, sizeof(buf), externalIV, key);
IORequest req; IORequest req;
@ -236,26 +202,21 @@ void CipherFileIO::initHeader( )
rDebug("initHeader finished, fileIV = %" PRIu64, fileIV); rDebug("initHeader finished, fileIV = %" PRIu64, fileIV);
} }
bool CipherFileIO::writeHeader( ) bool CipherFileIO::writeHeader() {
{ if (!base->isWritable()) {
if( !base->isWritable() )
{
// open for write.. // open for write..
int newFlags = lastFlags | O_RDWR; int newFlags = lastFlags | O_RDWR;
if( base->open( newFlags ) < 0 ) if (base->open(newFlags) < 0) {
{
rDebug("writeHeader failed to re-open for write"); rDebug("writeHeader failed to re-open for write");
return false; return false;
} }
} }
if(fileIV == 0) if (fileIV == 0) rError("Internal error: fileIV == 0 in writeHeader!!!");
rError("Internal error: fileIV == 0 in writeHeader!!!");
rDebug("writing fileIV %" PRIu64, fileIV); rDebug("writing fileIV %" PRIu64, fileIV);
unsigned char buf[8] = {0}; unsigned char buf[8] = {0};
for(int i=0; i<8; ++i) for (int i = 0; i < 8; ++i) {
{
buf[sizeof(buf) - 1 - i] = (unsigned char)(fileIV & 0xff); buf[sizeof(buf) - 1 - i] = (unsigned char)(fileIV & 0xff);
fileIV >>= 8; fileIV >>= 8;
} }
@ -272,8 +233,7 @@ bool CipherFileIO::writeHeader( )
return true; return true;
} }
ssize_t CipherFileIO::readOneBlock( const IORequest &req ) const ssize_t CipherFileIO::readOneBlock(const IORequest &req) const {
{
// read raw data, then decipher it.. // read raw data, then decipher it..
int bs = blockSize(); int bs = blockSize();
off_t blockNum = req.offset / bs; off_t blockNum = req.offset / bs;
@ -281,28 +241,23 @@ ssize_t CipherFileIO::readOneBlock( const IORequest &req ) const
ssize_t readSize = 0; ssize_t readSize = 0;
IORequest tmpReq = req; IORequest tmpReq = req;
if(haveHeader) if (haveHeader) tmpReq.offset += HEADER_SIZE;
tmpReq.offset += HEADER_SIZE;
readSize = base->read(tmpReq); readSize = base->read(tmpReq);
bool ok; bool ok;
if(readSize > 0) if (readSize > 0) {
{
if (haveHeader && fileIV == 0) if (haveHeader && fileIV == 0)
const_cast<CipherFileIO *>(this)->initHeader(); const_cast<CipherFileIO *>(this)->initHeader();
if(readSize != bs) if (readSize != bs) {
{
ok = streamRead(tmpReq.data, (int)readSize, blockNum ^ fileIV); ok = streamRead(tmpReq.data, (int)readSize, blockNum ^ fileIV);
} else } else {
{
ok = blockRead(tmpReq.data, (int)readSize, blockNum ^ fileIV); ok = blockRead(tmpReq.data, (int)readSize, blockNum ^ fileIV);
} }
if(!ok) if (!ok) {
{ rDebug("decodeBlock failed for block %" PRIi64 ", size %i", blockNum,
rDebug("decodeBlock failed for block %" PRIi64 ", size %i", (int)readSize);
blockNum, (int)readSize );
readSize = -1; readSize = -1;
} }
} else } else
@ -311,47 +266,36 @@ ssize_t CipherFileIO::readOneBlock( const IORequest &req ) const
return readSize; return readSize;
} }
bool CipherFileIO::writeOneBlock(const IORequest &req) {
bool CipherFileIO::writeOneBlock( const IORequest &req )
{
int bs = blockSize(); int bs = blockSize();
off_t blockNum = req.offset / bs; off_t blockNum = req.offset / bs;
if(haveHeader && fileIV == 0) if (haveHeader && fileIV == 0) initHeader();
initHeader();
bool ok; bool ok;
if( req.dataLen != bs ) if (req.dataLen != bs) {
{ ok = streamWrite(req.data, (int)req.dataLen, blockNum ^ fileIV);
ok = streamWrite( req.data, (int)req.dataLen, } else {
blockNum ^ fileIV ); ok = blockWrite(req.data, (int)req.dataLen, blockNum ^ fileIV);
} else
{
ok = blockWrite( req.data, (int)req.dataLen,
blockNum ^ fileIV );
} }
if( ok ) if (ok) {
{ if (haveHeader) {
if(haveHeader)
{
IORequest tmpReq = req; IORequest tmpReq = req;
tmpReq.offset += HEADER_SIZE; tmpReq.offset += HEADER_SIZE;
ok = base->write(tmpReq); ok = base->write(tmpReq);
} else } else
ok = base->write(req); ok = base->write(req);
} else } else {
{ rDebug("encodeBlock failed for block %" PRIi64 ", size %i", blockNum,
rDebug("encodeBlock failed for block %" PRIi64 ", size %i", req.dataLen);
blockNum, req.dataLen);
ok = false; ok = false;
} }
return ok; return ok;
} }
bool CipherFileIO::blockWrite(unsigned char *buf, int size, bool CipherFileIO::blockWrite(unsigned char *buf, int size,
uint64_t _iv64 ) const uint64_t _iv64) const {
{
if (!fsConfig->reverseEncryption) if (!fsConfig->reverseEncryption)
return cipher->blockEncode(buf, size, _iv64, key); return cipher->blockEncode(buf, size, _iv64, key);
else else
@ -359,28 +303,22 @@ bool CipherFileIO::blockWrite( unsigned char *buf, int size,
} }
bool CipherFileIO::streamWrite(unsigned char *buf, int size, bool CipherFileIO::streamWrite(unsigned char *buf, int size,
uint64_t _iv64 ) const uint64_t _iv64) const {
{
if (!fsConfig->reverseEncryption) if (!fsConfig->reverseEncryption)
return cipher->streamEncode(buf, size, _iv64, key); return cipher->streamEncode(buf, size, _iv64, key);
else else
return cipher->streamDecode(buf, size, _iv64, key); return cipher->streamDecode(buf, size, _iv64, key);
} }
bool CipherFileIO::blockRead(unsigned char *buf, int size, bool CipherFileIO::blockRead(unsigned char *buf, int size,
uint64_t _iv64 ) const uint64_t _iv64) const {
{
if (fsConfig->reverseEncryption) if (fsConfig->reverseEncryption)
return cipher->blockEncode(buf, size, _iv64, key); return cipher->blockEncode(buf, size, _iv64, key);
else else {
{ if (_allowHoles) {
if(_allowHoles)
{
// special case - leave all 0's alone // special case - leave all 0's alone
for (int i = 0; i < size; ++i) for (int i = 0; i < size; ++i)
if(buf[i] != 0) if (buf[i] != 0) return cipher->blockDecode(buf, size, _iv64, key);
return cipher->blockDecode( buf, size, _iv64, key );
return true; return true;
} else } else
@ -389,29 +327,21 @@ bool CipherFileIO::blockRead( unsigned char *buf, int size,
} }
bool CipherFileIO::streamRead(unsigned char *buf, int size, bool CipherFileIO::streamRead(unsigned char *buf, int size,
uint64_t _iv64 ) const uint64_t _iv64) const {
{
if (fsConfig->reverseEncryption) if (fsConfig->reverseEncryption)
return cipher->streamEncode(buf, size, _iv64, key); return cipher->streamEncode(buf, size, _iv64, key);
else else
return cipher->streamDecode(buf, size, _iv64, key); return cipher->streamDecode(buf, size, _iv64, key);
} }
int CipherFileIO::truncate(off_t size) {
int CipherFileIO::truncate( off_t size )
{
int res = 0; int res = 0;
if(!haveHeader) if (!haveHeader) {
{
res = BlockFileIO::truncateBase(size, base.get()); res = BlockFileIO::truncateBase(size, base.get());
} else } else {
{ if (0 == fileIV) {
if(0 == fileIV)
{
// empty file.. create the header.. // empty file.. create the header..
if( !base->isWritable() ) if (!base->isWritable()) {
{
// open for write.. // open for write..
int newFlags = lastFlags | O_RDWR; int newFlags = lastFlags | O_RDWR;
if (base->open(newFlags) < 0) if (base->open(newFlags) < 0)
@ -424,14 +354,9 @@ int CipherFileIO::truncate( off_t size )
// the wrong size.. // the wrong size..
res = BlockFileIO::truncateBase(size, 0); res = BlockFileIO::truncateBase(size, 0);
if(res == 0) if (res == 0) base->truncate(size + HEADER_SIZE);
base->truncate( size + HEADER_SIZE );
} }
return res; return res;
} }
bool CipherFileIO::isWritable() const bool CipherFileIO::isWritable() const { return base->isWritable(); }
{
return base->isWritable();
}

View File

@ -34,11 +34,9 @@ class Cipher;
Uses BlockFileIO to handle the block scatter / gather issues. Uses BlockFileIO to handle the block scatter / gather issues.
*/ */
class CipherFileIO : public BlockFileIO class CipherFileIO : public BlockFileIO {
{
public: public:
CipherFileIO( const shared_ptr<FileIO> &base, CipherFileIO(const shared_ptr<FileIO> &base, const FSConfigPtr &cfg);
const FSConfigPtr &cfg);
virtual ~CipherFileIO(); virtual ~CipherFileIO();
virtual rel::Interface interface() const; virtual rel::Interface interface() const;
@ -62,14 +60,10 @@ private:
void initHeader(); void initHeader();
bool writeHeader(); bool writeHeader();
bool blockRead( unsigned char *buf, int size, bool blockRead(unsigned char *buf, int size, uint64_t iv64) const;
uint64_t iv64 ) const; bool streamRead(unsigned char *buf, int size, uint64_t iv64) const;
bool streamRead( unsigned char *buf, int size, bool blockWrite(unsigned char *buf, int size, uint64_t iv64) const;
uint64_t iv64 ) const; bool streamWrite(unsigned char *buf, int size, uint64_t iv64) const;
bool blockWrite( unsigned char *buf, int size,
uint64_t iv64 ) const;
bool streamWrite( unsigned char *buf, int size,
uint64_t iv64 ) const;
shared_ptr<FileIO> base; shared_ptr<FileIO> base;

View File

@ -20,11 +20,6 @@
#include "CipherKey.h" #include "CipherKey.h"
AbstractCipherKey::AbstractCipherKey() AbstractCipherKey::AbstractCipherKey() {}
{
}
AbstractCipherKey::~AbstractCipherKey()
{
}
AbstractCipherKey::~AbstractCipherKey() {}

View File

@ -23,8 +23,7 @@
#include "shared_ptr.h" #include "shared_ptr.h"
class AbstractCipherKey class AbstractCipherKey {
{
public: public:
AbstractCipherKey(); AbstractCipherKey();
virtual ~AbstractCipherKey(); virtual ~AbstractCipherKey();
@ -33,4 +32,3 @@ public:
typedef shared_ptr<AbstractCipherKey> CipherKey; typedef shared_ptr<AbstractCipherKey> CipherKey;
#endif #endif

View File

@ -28,44 +28,33 @@
#include <unistd.h> #include <unistd.h>
#include <cstring> #include <cstring>
using namespace std; using namespace std;
using namespace rlog; using namespace rlog;
ConfigReader::ConfigReader() {}
ConfigReader::ConfigReader() ConfigReader::~ConfigReader() {}
{
}
ConfigReader::~ConfigReader()
{
}
// read the entire file into a ConfigVar instance and then use that to decode // read the entire file into a ConfigVar instance and then use that to decode
// into mapped variables. // into mapped variables.
bool bool ConfigReader::load(const char *fileName) {
ConfigReader::load(const char *fileName)
{
struct stat stbuf; struct stat stbuf;
memset(&stbuf, 0, sizeof(struct stat)); memset(&stbuf, 0, sizeof(struct stat));
if( lstat( fileName, &stbuf ) != 0) if (lstat(fileName, &stbuf) != 0) return false;
return false;
int size = stbuf.st_size; int size = stbuf.st_size;
int fd = open(fileName, O_RDONLY); int fd = open(fileName, O_RDONLY);
if(fd < 0) if (fd < 0) return false;
return false;
char *buf = new char[size]; char *buf = new char[size];
int res = ::read(fd, buf, size); int res = ::read(fd, buf, size);
close(fd); close(fd);
if( res != size ) if (res != size) {
{ rWarning("Partial read of config file, expecting %i bytes, got %i", size,
rWarning("Partial read of config file, expecting %i bytes, got %i", res);
size, res);
delete[] buf; delete[] buf;
return false; return false;
} }
@ -77,21 +66,17 @@ ConfigReader::load(const char *fileName)
return loadFromVar(in); return loadFromVar(in);
} }
bool bool ConfigReader::loadFromVar(ConfigVar &in) {
ConfigReader::loadFromVar(ConfigVar &in)
{
in.resetOffset(); in.resetOffset();
// parse. // parse.
int numEntries = in.readInt(); int numEntries = in.readInt();
for(int i=0; i<numEntries; ++i) for (int i = 0; i < numEntries; ++i) {
{
string key, value; string key, value;
in >> key >> value; in >> key >> value;
if(key.length() == 0) if (key.length() == 0) {
{
rError("Invalid key encoding in buffer"); rError("Invalid key encoding in buffer");
return false; return false;
} }
@ -102,24 +87,19 @@ ConfigReader::loadFromVar(ConfigVar &in)
return true; return true;
} }
bool bool ConfigReader::save(const char *fileName) const {
ConfigReader::save(const char *fileName) const
{
// write everything to a ConfigVar, then output to disk // write everything to a ConfigVar, then output to disk
ConfigVar out = toVar(); ConfigVar out = toVar();
int fd = ::open(fileName, O_RDWR | O_CREAT, 0640); int fd = ::open(fileName, O_RDWR | O_CREAT, 0640);
if(fd >= 0) if (fd >= 0) {
{
int retVal = ::write(fd, out.buffer(), out.size()); int retVal = ::write(fd, out.buffer(), out.size());
close(fd); close(fd);
if(retVal != out.size()) if (retVal != out.size()) {
{
rError("Error writing to config file %s", fileName); rError("Error writing to config file %s", fileName);
return false; return false;
} }
} else } else {
{
rError("Unable to open or create file %s", fileName); rError("Unable to open or create file %s", fileName);
return false; return false;
} }
@ -127,15 +107,12 @@ ConfigReader::save(const char *fileName) const
return true; return true;
} }
ConfigVar ConfigVar ConfigReader::toVar() const {
ConfigReader::toVar() const
{
// write everything to a ConfigVar, then output to disk // write everything to a ConfigVar, then output to disk
ConfigVar out; ConfigVar out;
out.writeInt(vars.size()); out.writeInt(vars.size());
map<string, ConfigVar>::const_iterator it; map<string, ConfigVar>::const_iterator it;
for(it = vars.begin(); it != vars.end(); ++it) for (it = vars.begin(); it != vars.end(); ++it) {
{
out.writeInt(it->first.size()); out.writeInt(it->first.size());
out.write((unsigned char *)it->first.data(), it->first.size()); out.write((unsigned char *)it->first.data(), it->first.size());
out.writeInt(it->second.size()); out.writeInt(it->second.size());
@ -145,8 +122,7 @@ ConfigReader::toVar() const
return out; return out;
} }
ConfigVar ConfigReader::operator[] ( const std::string &varName ) const ConfigVar ConfigReader::operator[](const std::string &varName) const {
{
// read only // read only
map<string, ConfigVar>::const_iterator it = vars.find(varName); map<string, ConfigVar>::const_iterator it = vars.find(varName);
if (it == vars.end()) if (it == vars.end())
@ -155,8 +131,6 @@ ConfigVar ConfigReader::operator[] ( const std::string &varName ) const
return it->second; return it->second;
} }
ConfigVar &ConfigReader::operator[] ( const std::string &varName ) ConfigVar &ConfigReader::operator[](const std::string &varName) {
{
return vars[varName]; return vars[varName];
} }

View File

@ -43,8 +43,7 @@
ConfigReader cfg; ConfigReader cfg;
cfg["cipher"] << cipher->interface(); cfg["cipher"] << cipher->interface();
*/ */
class ConfigReader class ConfigReader {
{
public: public:
ConfigReader(); ConfigReader();
~ConfigReader(); ~ConfigReader();
@ -62,5 +61,4 @@ private:
std::map<std::string, ConfigVar> vars; std::map<std::string, ConfigVar> vars;
}; };
#endif #endif

View File

@ -26,38 +26,21 @@
using namespace rlog; using namespace rlog;
#ifndef MIN #ifndef MIN
inline int MIN(int a, int b) inline int MIN(int a, int b) { return (a < b) ? a : b; }
{
return (a < b) ? a : b;
}
#endif #endif
ConfigVar::ConfigVar() : pd(new ConfigVarData) { pd->offset = 0; }
ConfigVar::ConfigVar() ConfigVar::ConfigVar(const std::string &buf) : pd(new ConfigVarData) {
: pd( new ConfigVarData )
{
pd->offset = 0;
}
ConfigVar::ConfigVar(const std::string &buf)
: pd( new ConfigVarData )
{
pd->buffer = buf; pd->buffer = buf;
pd->offset = 0; pd->offset = 0;
} }
ConfigVar::ConfigVar(const ConfigVar &src) ConfigVar::ConfigVar(const ConfigVar &src) { pd = src.pd; }
{
pd = src.pd;
}
ConfigVar::~ConfigVar() ConfigVar::~ConfigVar() { pd.reset(); }
{
pd.reset();
}
ConfigVar & ConfigVar::operator = (const ConfigVar &src) ConfigVar &ConfigVar::operator=(const ConfigVar &src) {
{
if (src.pd == pd) if (src.pd == pd)
return *this; return *this;
else else
@ -66,30 +49,22 @@ ConfigVar & ConfigVar::operator = (const ConfigVar &src)
return *this; return *this;
} }
void ConfigVar::resetOffset() void ConfigVar::resetOffset() { pd->offset = 0; }
{
pd->offset = 0;
}
int ConfigVar::read(unsigned char *buffer_, int bytes) const int ConfigVar::read(unsigned char *buffer_, int bytes) const {
{
int toCopy = MIN(bytes, pd->buffer.size() - pd->offset); int toCopy = MIN(bytes, pd->buffer.size() - pd->offset);
if(toCopy > 0) if (toCopy > 0) memcpy(buffer_, pd->buffer.data() + pd->offset, toCopy);
memcpy( buffer_, pd->buffer.data() + pd->offset, toCopy );
pd->offset += toCopy; pd->offset += toCopy;
return toCopy; return toCopy;
} }
int ConfigVar::write(const unsigned char *data, int bytes) int ConfigVar::write(const unsigned char *data, int bytes) {
{ if (pd->buffer.size() == (unsigned int)pd->offset) {
if(pd->buffer.size() == (unsigned int)pd->offset)
{
pd->buffer.append((const char *)data, bytes); pd->buffer.append((const char *)data, bytes);
} else } else {
{
pd->buffer.insert(pd->offset, (const char *)data, bytes); pd->buffer.insert(pd->offset, (const char *)data, bytes);
} }
@ -98,31 +73,19 @@ int ConfigVar::write(const unsigned char *data, int bytes)
return bytes; return bytes;
} }
int ConfigVar::size() const int ConfigVar::size() const { return pd->buffer.size(); }
{
return pd->buffer.size();
}
const char *ConfigVar::buffer() const const char *ConfigVar::buffer() const { return pd->buffer.data(); }
{
return pd->buffer.data();
}
int ConfigVar::at() const int ConfigVar::at() const { return pd->offset; }
{
return pd->offset;
}
void ConfigVar::writeString(const char *data, int bytes) void ConfigVar::writeString(const char *data, int bytes) {
{
writeInt(bytes); writeInt(bytes);
write((const unsigned char *)data, bytes); write((const unsigned char *)data, bytes);
} }
// convert integer to BER encoded integer // convert integer to BER encoded integer
void ConfigVar::writeInt(int val) void ConfigVar::writeInt(int val) {
{
// we can represent 7 bits per char output, so a 32bit number may take up // we can represent 7 bits per char output, so a 32bit number may take up
// to 5 bytes. // to 5 bytes.
// first byte: 0x0000007f 0111,1111 // first byte: 0x0000007f 0111,1111
@ -141,14 +104,12 @@ void ConfigVar::writeInt(int val)
// find the starting point - we only need to output starting at the most // find the starting point - we only need to output starting at the most
// significant non-zero digit.. // significant non-zero digit..
int start = 0; int start = 0;
while(digit[start] == 0x80) while (digit[start] == 0x80) ++start;
++start;
write(digit + start, 5 - start); write(digit + start, 5 - start);
} }
int ConfigVar::readInt() const int ConfigVar::readInt() const {
{
const unsigned char *buf = (const unsigned char *)buffer(); const unsigned char *buf = (const unsigned char *)buffer();
int bytes = this->size(); int bytes = this->size();
int offset = at(); int offset = at();
@ -157,8 +118,7 @@ int ConfigVar::readInt() const
rAssert(offset < bytes); rAssert(offset < bytes);
do do {
{
unsigned char tmp = buf[offset++]; unsigned char tmp = buf[offset++];
highBitSet = tmp & 0x80; highBitSet = tmp & 0x80;
@ -173,8 +133,7 @@ int ConfigVar::readInt() const
return value; return value;
} }
int ConfigVar::readInt( int defaultValue ) const int ConfigVar::readInt(int defaultValue) const {
{
int bytes = this->size(); int bytes = this->size();
int offset = at(); int offset = at();
@ -184,69 +143,58 @@ int ConfigVar::readInt( int defaultValue ) const
return readInt(); return readInt();
} }
bool ConfigVar::readBool( bool defaultValue ) const bool ConfigVar::readBool(bool defaultValue) const {
{
int tmp = readInt(defaultValue ? 1 : 0); int tmp = readInt(defaultValue ? 1 : 0);
return (tmp != 0); return (tmp != 0);
} }
ConfigVar & operator << (ConfigVar &src, bool value) ConfigVar &operator<<(ConfigVar &src, bool value) {
{
src.writeInt(value ? 1 : 0); src.writeInt(value ? 1 : 0);
return src; return src;
} }
ConfigVar & operator << (ConfigVar &src, int var) ConfigVar &operator<<(ConfigVar &src, int var) {
{
src.writeInt(var); src.writeInt(var);
return src; return src;
} }
ConfigVar & operator << (ConfigVar &src, const std::string &str) ConfigVar &operator<<(ConfigVar &src, const std::string &str) {
{
src.writeString(str.data(), str.length()); src.writeString(str.data(), str.length());
return src; return src;
} }
const ConfigVar & operator >> (const ConfigVar &src, bool &result) const ConfigVar &operator>>(const ConfigVar &src, bool &result) {
{
int tmp = src.readInt(); int tmp = src.readInt();
result = (tmp != 0); result = (tmp != 0);
return src; return src;
} }
const ConfigVar & operator >> (const ConfigVar &src, int &result) const ConfigVar &operator>>(const ConfigVar &src, int &result) {
{
result = src.readInt(); result = src.readInt();
return src; return src;
} }
const ConfigVar & operator >> (const ConfigVar &src, std::string &result) const ConfigVar &operator>>(const ConfigVar &src, std::string &result) {
{
int length = src.readInt(); int length = src.readInt();
// rAssert(length > 0); // rAssert(length > 0);
int readLen; int readLen;
unsigned char tmpBuf[32]; unsigned char tmpBuf[32];
if(length > (int)sizeof(tmpBuf)) if (length > (int)sizeof(tmpBuf)) {
{
unsigned char *ptr = new unsigned char[length]; unsigned char *ptr = new unsigned char[length];
readLen = src.read(ptr, length); readLen = src.read(ptr, length);
result.assign((char *)ptr, length); result.assign((char *)ptr, length);
delete[] ptr; delete[] ptr;
} else } else {
{
readLen = src.read(tmpBuf, length); readLen = src.read(tmpBuf, length);
result.assign((char *)tmpBuf, length); result.assign((char *)tmpBuf, length);
} }
if(readLen != length) if (readLen != length) {
{
rDebug("string encoded as size %i bytes, read %i", length, readLen); rDebug("string encoded as size %i bytes, read %i", length, readLen);
} }
rAssert(readLen == length); rAssert(readLen == length);
return src; return src;
} }

View File

@ -24,10 +24,8 @@
#include <string> #include <string>
#include "shared_ptr.h" #include "shared_ptr.h"
class ConfigVar class ConfigVar {
{ struct ConfigVarData {
struct ConfigVarData
{
std::string buffer; std::string buffer;
int offset; int offset;
}; };
@ -78,4 +76,3 @@ const ConfigVar & operator >> (const ConfigVar &, int &);
const ConfigVar &operator>>(const ConfigVar &, std::string &str); const ConfigVar &operator>>(const ConfigVar &, std::string &str);
#endif #endif

View File

@ -29,8 +29,7 @@
using namespace rel; using namespace rel;
using namespace rlog; using namespace rlog;
EncFS_Context::EncFS_Context() EncFS_Context::EncFS_Context() {
{
pthread_cond_init(&wakeupCond, 0); pthread_cond_init(&wakeupCond, 0);
pthread_mutex_init(&wakeupMutex, 0); pthread_mutex_init(&wakeupMutex, 0);
pthread_mutex_init(&contextMutex, 0); pthread_mutex_init(&contextMutex, 0);
@ -38,8 +37,7 @@ EncFS_Context::EncFS_Context()
usageCount = 0; usageCount = 0;
} }
EncFS_Context::~EncFS_Context() EncFS_Context::~EncFS_Context() {
{
pthread_mutex_destroy(&contextMutex); pthread_mutex_destroy(&contextMutex);
pthread_mutex_destroy(&wakeupMutex); pthread_mutex_destroy(&wakeupMutex);
pthread_cond_destroy(&wakeupCond); pthread_cond_destroy(&wakeupCond);
@ -48,22 +46,18 @@ EncFS_Context::~EncFS_Context()
openFiles.clear(); openFiles.clear();
} }
shared_ptr<DirNode> EncFS_Context::getRoot(int *errCode) shared_ptr<DirNode> EncFS_Context::getRoot(int *errCode) {
{
shared_ptr<DirNode> ret; shared_ptr<DirNode> ret;
do do {
{
{ {
Lock lock(contextMutex); Lock lock(contextMutex);
ret = root; ret = root;
++usageCount; ++usageCount;
} }
if(!ret) if (!ret) {
{
int res = remountFS(this); int res = remountFS(this);
if(res != 0) if (res != 0) {
{
*errCode = res; *errCode = res;
break; break;
} }
@ -73,22 +67,16 @@ shared_ptr<DirNode> EncFS_Context::getRoot(int *errCode)
return ret; return ret;
} }
void EncFS_Context::setRoot(const shared_ptr<DirNode> &r) void EncFS_Context::setRoot(const shared_ptr<DirNode> &r) {
{
Lock lock(contextMutex); Lock lock(contextMutex);
root = r; root = r;
if(r) if (r) rootCipherDir = r->rootDirectory();
rootCipherDir = r->rootDirectory();
} }
bool EncFS_Context::isMounted() bool EncFS_Context::isMounted() { return root; }
{
return root;
}
int EncFS_Context::getAndResetUsageCounter() int EncFS_Context::getAndResetUsageCounter() {
{
Lock lock(contextMutex); Lock lock(contextMutex);
int count = usageCount; int count = usageCount;
@ -97,51 +85,43 @@ int EncFS_Context::getAndResetUsageCounter()
return count; return count;
} }
int EncFS_Context::openFileCount() const int EncFS_Context::openFileCount() const {
{
Lock lock(contextMutex); Lock lock(contextMutex);
return openFiles.size(); return openFiles.size();
} }
shared_ptr<FileNode> EncFS_Context::lookupNode(const char *path) shared_ptr<FileNode> EncFS_Context::lookupNode(const char *path) {
{
Lock lock(contextMutex); Lock lock(contextMutex);
FileMap::iterator it = openFiles.find(std::string(path)); FileMap::iterator it = openFiles.find(std::string(path));
if(it != openFiles.end()) if (it != openFiles.end()) {
{
// all the items in the set point to the same node.. so just use the // all the items in the set point to the same node.. so just use the
// first // first
return (*it->second.begin())->node; return (*it->second.begin())->node;
} else } else {
{
return shared_ptr<FileNode>(); return shared_ptr<FileNode>();
} }
} }
void EncFS_Context::renameNode(const char *from, const char *to) void EncFS_Context::renameNode(const char *from, const char *to) {
{
Lock lock(contextMutex); Lock lock(contextMutex);
FileMap::iterator it = openFiles.find(std::string(from)); FileMap::iterator it = openFiles.find(std::string(from));
if(it != openFiles.end()) if (it != openFiles.end()) {
{
std::set<Placeholder *> val = it->second; std::set<Placeholder *> val = it->second;
openFiles.erase(it); openFiles.erase(it);
openFiles[std::string(to)] = val; openFiles[std::string(to)] = val;
} }
} }
shared_ptr<FileNode> EncFS_Context::getNode(void *pl) shared_ptr<FileNode> EncFS_Context::getNode(void *pl) {
{
Placeholder *ph = (Placeholder *)pl; Placeholder *ph = (Placeholder *)pl;
return ph->node; return ph->node;
} }
void *EncFS_Context::putNode(const char *path, void *EncFS_Context::putNode(const char *path,
const shared_ptr<FileNode> &node) const shared_ptr<FileNode> &node) {
{
Lock lock(contextMutex); Lock lock(contextMutex);
Placeholder *pl = new Placeholder(node); Placeholder *pl = new Placeholder(node);
openFiles[std::string(path)].insert(pl); openFiles[std::string(path)].insert(pl);
@ -149,8 +129,7 @@ void *EncFS_Context::putNode(const char *path,
return (void *)pl; return (void *)pl;
} }
void EncFS_Context::eraseNode(const char *path, void *pl) void EncFS_Context::eraseNode(const char *path, void *pl) {
{
Lock lock(contextMutex); Lock lock(contextMutex);
Placeholder *ph = (Placeholder *)pl; Placeholder *ph = (Placeholder *)pl;
@ -163,8 +142,7 @@ void EncFS_Context::eraseNode(const char *path, void *pl)
rAssert(rmCount == 1); rAssert(rmCount == 1);
// if no more references to this file, remove the record all together // if no more references to this file, remove the record all together
if(it->second.empty()) if (it->second.empty()) {
{
// attempts to make use of shallow copy to clear memory used to hold // attempts to make use of shallow copy to clear memory used to hold
// unencrypted filenames.. not sure this does any good.. // unencrypted filenames.. not sure this does any good..
std::string storedName = it->first; std::string storedName = it->first;
@ -174,4 +152,3 @@ void EncFS_Context::eraseNode(const char *path, void *pl)
delete ph; delete ph;
} }

View File

@ -37,8 +37,7 @@ struct EncFS_Opts;
class FileNode; class FileNode;
class DirNode; class DirNode;
class EncFS_Context class EncFS_Context {
{
public: public:
EncFS_Context(); EncFS_Context();
~EncFS_Context(); ~EncFS_Context();
@ -82,20 +81,17 @@ private:
* release() is called. shared_ptr then does our reference counting for * release() is called. shared_ptr then does our reference counting for
* us. * us.
*/ */
struct Placeholder struct Placeholder {
{
shared_ptr<FileNode> node; shared_ptr<FileNode> node;
Placeholder(const shared_ptr<FileNode> &ptr) : node(ptr) {} Placeholder(const shared_ptr<FileNode> &ptr) : node(ptr) {}
}; };
// set of open files, indexed by path
#ifdef USE_HASHMAP #ifdef USE_HASHMAP
typedef __gnu_cxx::hash_map<std::string, // set of open files, indexed by path
std::set<Placeholder*> > FileMap; typedef __gnu_cxx::hash_map<std::string, std::set<Placeholder *> > FileMap;
#else #else
typedef std::map< std::string, typedef std::map<std::string, std::set<Placeholder *> > FileMap;
std::set<Placeholder*> > FileMap;
#endif #endif
mutable pthread_mutex_t contextMutex; mutable pthread_mutex_t contextMutex;
@ -108,4 +104,3 @@ private:
int remountFS(EncFS_Context *ctx); int remountFS(EncFS_Context *ctx);
#endif #endif

View File

@ -50,33 +50,19 @@ using namespace rlog;
static RLogChannel *Info = DEF_CHANNEL("info/DirNode", Log_Info); static RLogChannel *Info = DEF_CHANNEL("info/DirNode", Log_Info);
class DirDeleter class DirDeleter {
{
public: public:
void operator () ( DIR *d ) void operator()(DIR *d) { ::closedir(d); }
{
::closedir( d );
}
}; };
DirTraverse::DirTraverse(const shared_ptr<DIR> &_dirPtr, uint64_t _iv,
DirTraverse::DirTraverse(const shared_ptr<DIR> &_dirPtr, const shared_ptr<NameIO> &_naming)
uint64_t _iv, const shared_ptr<NameIO> &_naming) : dir(_dirPtr), iv(_iv), naming(_naming) {}
: dir( _dirPtr )
, iv( _iv )
, naming( _naming )
{
}
DirTraverse::DirTraverse(const DirTraverse &src) DirTraverse::DirTraverse(const DirTraverse &src)
: dir( src.dir ) : dir(src.dir), iv(src.iv), naming(src.naming) {}
, iv( src.iv )
, naming( src.naming )
{
}
DirTraverse &DirTraverse::operator = (const DirTraverse &src) DirTraverse &DirTraverse::operator=(const DirTraverse &src) {
{
dir = src.dir; dir = src.dir;
iv = src.iv; iv = src.iv;
naming = src.naming; naming = src.naming;
@ -84,23 +70,18 @@ DirTraverse &DirTraverse::operator = (const DirTraverse &src)
return *this; return *this;
} }
DirTraverse::~DirTraverse() DirTraverse::~DirTraverse() {
{
dir.reset(); dir.reset();
iv = 0; iv = 0;
naming.reset(); naming.reset();
} }
static static bool _nextName(struct dirent *&de, const shared_ptr<DIR> &dir,
bool _nextName(struct dirent *&de, const shared_ptr<DIR> &dir, int *fileType, ino_t *inode) {
int *fileType, ino_t *inode)
{
de = ::readdir(dir.get()); de = ::readdir(dir.get());
if(de) if (de) {
{ if (fileType) {
if(fileType)
{
#if defined(_DIRENT_HAVE_D_TYPE) || defined(__FreeBSD__) || defined(__APPLE__) #if defined(_DIRENT_HAVE_D_TYPE) || defined(__FreeBSD__) || defined(__APPLE__)
*fileType = de->d_type; *fileType = de->d_type;
#else #else
@ -108,29 +89,22 @@ bool _nextName(struct dirent *&de, const shared_ptr<DIR> &dir,
*fileType = 0; *fileType = 0;
#endif #endif
} }
if(inode) if (inode) *inode = de->d_ino;
*inode = de->d_ino;
return true; return true;
} else } else {
{ if (fileType) *fileType = 0;
if(fileType)
*fileType = 0;
return false; return false;
} }
} }
std::string DirTraverse::nextPlaintextName(int *fileType, ino_t *inode) {
std::string DirTraverse::nextPlaintextName(int *fileType, ino_t *inode)
{
struct dirent *de = 0; struct dirent *de = 0;
while(_nextName(de, dir, fileType, inode)) while (_nextName(de, dir, fileType, inode)) {
{ try {
try
{
uint64_t localIv = iv; uint64_t localIv = iv;
return naming->decodePath(de->d_name, &localIv); return naming->decodePath(de->d_name, &localIv);
} catch ( rlog::Error &ex ) }
{ catch (rlog::Error &ex) {
// .. .problem decoding, ignore it and continue on to next name.. // .. .problem decoding, ignore it and continue on to next name..
rDebug("error decoding filename: %s", de->d_name); rDebug("error decoding filename: %s", de->d_name);
} }
@ -139,19 +113,16 @@ std::string DirTraverse::nextPlaintextName(int *fileType, ino_t *inode)
return string(); return string();
} }
std::string DirTraverse::nextInvalid() std::string DirTraverse::nextInvalid() {
{
struct dirent *de = 0; struct dirent *de = 0;
// find the first name which produces a decoding error... // find the first name which produces a decoding error...
while(_nextName(de, dir, (int*)0, (ino_t*)0)) while (_nextName(de, dir, (int *)0, (ino_t *)0)) {
{ try {
try
{
uint64_t localIv = iv; uint64_t localIv = iv;
naming->decodePath(de->d_name, &localIv); naming->decodePath(de->d_name, &localIv);
continue; continue;
} catch( rlog::Error &ex ) }
{ catch (rlog::Error &ex) {
return string(de->d_name); return string(de->d_name);
} }
} }
@ -159,8 +130,7 @@ std::string DirTraverse::nextInvalid()
return string(); return string();
} }
struct RenameEl struct RenameEl {
{
// ciphertext names // ciphertext names
string oldCName; string oldCName;
string newCName; // intermediate name (not final cname) string newCName; // intermediate name (not final cname)
@ -172,8 +142,7 @@ struct RenameEl
bool isDirectory; bool isDirectory;
}; };
class RenameOp class RenameOp {
{
private: private:
DirNode *dn; DirNode *dn;
shared_ptr<list<RenameEl> > renameList; shared_ptr<list<RenameEl> > renameList;
@ -181,74 +150,55 @@ private:
public: public:
RenameOp(DirNode *_dn, const shared_ptr<list<RenameEl> > &_renameList) RenameOp(DirNode *_dn, const shared_ptr<list<RenameEl> > &_renameList)
: dn(_dn), renameList(_renameList) : dn(_dn), renameList(_renameList) {
{
last = renameList->begin(); last = renameList->begin();
} }
RenameOp(const RenameOp &src) RenameOp(const RenameOp &src)
: dn(src.dn) : dn(src.dn), renameList(src.renameList), last(src.last) {}
, renameList(src.renameList)
, last(src.last)
{
}
~RenameOp(); ~RenameOp();
operator bool () const operator bool() const { return renameList; }
{
return renameList;
}
bool apply(); bool apply();
void undo(); void undo();
}; };
RenameOp::~RenameOp() RenameOp::~RenameOp() {
{ if (renameList) {
if(renameList)
{
// got a bunch of decoded filenames sitting in memory.. do a little // got a bunch of decoded filenames sitting in memory.. do a little
// cleanup before leaving.. // cleanup before leaving..
list<RenameEl>::iterator it; list<RenameEl>::iterator it;
for(it = renameList->begin(); it != renameList->end(); ++it) for (it = renameList->begin(); it != renameList->end(); ++it) {
{
it->oldPName.assign(it->oldPName.size(), ' '); it->oldPName.assign(it->oldPName.size(), ' ');
it->newPName.assign(it->newPName.size(), ' '); it->newPName.assign(it->newPName.size(), ' ');
} }
} }
} }
bool RenameOp::apply() bool RenameOp::apply() {
{ try {
try while (last != renameList->end()) {
{
while(last != renameList->end())
{
// backing store rename. // backing store rename.
rDebug("renaming %s -> %s", rDebug("renaming %s -> %s", last->oldCName.c_str(),
last->oldCName.c_str(), last->newCName.c_str()); last->newCName.c_str());
struct stat st; struct stat st;
bool preserve_mtime = ::stat(last->oldCName.c_str(), &st) == 0; bool preserve_mtime = ::stat(last->oldCName.c_str(), &st) == 0;
// internal node rename.. // internal node rename..
dn->renameNode( last->oldPName.c_str(), dn->renameNode(last->oldPName.c_str(), last->newPName.c_str());
last->newPName.c_str() );
// rename on disk.. // rename on disk..
if(::rename( last->oldCName.c_str(), if (::rename(last->oldCName.c_str(), last->newCName.c_str()) == -1) {
last->newCName.c_str() ) == -1) rWarning("Error renaming %s: %s", last->oldCName.c_str(),
{ strerror(errno));
rWarning("Error renaming %s: %s", dn->renameNode(last->newPName.c_str(), last->oldPName.c_str(), false);
last->oldCName.c_str(), strerror( errno ));
dn->renameNode( last->newPName.c_str(),
last->oldPName.c_str(), false );
return false; return false;
} }
if(preserve_mtime) if (preserve_mtime) {
{
struct utimbuf ut; struct utimbuf ut;
ut.actime = st.st_atime; ut.actime = st.st_atime;
ut.modtime = st.st_mtime; ut.modtime = st.st_mtime;
@ -259,19 +209,17 @@ bool RenameOp::apply()
} }
return true; return true;
} catch( rlog::Error &err ) }
{ catch (rlog::Error &err) {
err.log(_RLWarningChannel); err.log(_RLWarningChannel);
return false; return false;
} }
} }
void RenameOp::undo() void RenameOp::undo() {
{
rDebug("in undoRename"); rDebug("in undoRename");
if(last == renameList->begin()) if (last == renameList->begin()) {
{
rDebug("nothing to undo"); rDebug("nothing to undo");
return; // nothing to undo return; // nothing to undo
} }
@ -281,20 +229,17 @@ void RenameOp::undo()
int undoCount = 0; int undoCount = 0;
list<RenameEl>::const_iterator it = last; list<RenameEl>::const_iterator it = last;
while( it != renameList->begin() ) while (it != renameList->begin()) {
{
--it; --it;
rDebug("undo: renaming %s -> %s", rDebug("undo: renaming %s -> %s", it->newCName.c_str(),
it->newCName.c_str(), it->oldCName.c_str()); it->oldCName.c_str());
::rename(it->newCName.c_str(), it->oldCName.c_str()); ::rename(it->newCName.c_str(), it->oldCName.c_str());
try try {
{ dn->renameNode(it->newPName.c_str(), it->oldPName.c_str(), false);
dn->renameNode( it->newPName.c_str(), }
it->oldPName.c_str(), false ); catch (rlog::Error &err) {
} catch( rlog::Error &err )
{
err.log(_RLWarningChannel); err.log(_RLWarningChannel);
// continue on anyway... // continue on anyway...
} }
@ -304,10 +249,8 @@ void RenameOp::undo()
rWarning("Undo rename count: %i", undoCount); rWarning("Undo rename count: %i", undoCount);
} }
DirNode::DirNode(EncFS_Context *_ctx, DirNode::DirNode(EncFS_Context *_ctx, const string &sourceDir,
const string &sourceDir, const FSConfigPtr &_config) {
const FSConfigPtr &_config)
{
pthread_mutex_init(&mutex, 0); pthread_mutex_init(&mutex, 0);
Lock _lock(mutex); Lock _lock(mutex);
@ -318,67 +261,47 @@ DirNode::DirNode(EncFS_Context *_ctx,
// make sure rootDir ends in '/', so that we can form a path by appending // make sure rootDir ends in '/', so that we can form a path by appending
// the rest.. // the rest..
if( rootDir[ rootDir.length()-1 ] != '/' ) if (rootDir[rootDir.length() - 1] != '/') rootDir.append(1, '/');
rootDir.append( 1, '/');
naming = fsConfig->nameCoding; naming = fsConfig->nameCoding;
} }
DirNode::~DirNode() DirNode::~DirNode() {}
{
}
bool bool DirNode::hasDirectoryNameDependency() const {
DirNode::hasDirectoryNameDependency() const
{
return naming ? naming->getChainedNameIV() : false; return naming ? naming->getChainedNameIV() : false;
} }
string string DirNode::rootDirectory() {
DirNode::rootDirectory()
{
// don't update last access here, otherwise 'du' would cause lastAccess to // don't update last access here, otherwise 'du' would cause lastAccess to
// be reset. // be reset.
// chop off '/' terminator from root dir. // chop off '/' terminator from root dir.
return string(rootDir, 0, rootDir.length() - 1); return string(rootDir, 0, rootDir.length() - 1);
} }
string string DirNode::cipherPath(const char *plaintextPath) {
DirNode::cipherPath( const char *plaintextPath )
{
return rootDir + naming->encodePath(plaintextPath); return rootDir + naming->encodePath(plaintextPath);
} }
string string DirNode::cipherPathWithoutRoot(const char *plaintextPath) {
DirNode::cipherPathWithoutRoot( const char *plaintextPath )
{
return naming->encodePath(plaintextPath); return naming->encodePath(plaintextPath);
} }
string string DirNode::plainPath(const char *cipherPath_) {
DirNode::plainPath( const char *cipherPath_ ) try {
{ if (!strncmp(cipherPath_, rootDir.c_str(), rootDir.length())) {
try
{
if( !strncmp( cipherPath_, rootDir.c_str(),
rootDir.length() ) )
{
return naming->decodePath(cipherPath_ + rootDir.length()); return naming->decodePath(cipherPath_ + rootDir.length());
} else } else {
{ if (cipherPath_[0] == '+') {
if ( cipherPath_[0] == '+' )
{
// decode as fully qualified path // decode as fully qualified path
return string("/") + naming->decodeName( cipherPath_+1, return string("/") +
strlen(cipherPath_+1) ); naming->decodeName(cipherPath_ + 1, strlen(cipherPath_ + 1));
} else } else {
{
return naming->decodePath(cipherPath_); return naming->decodePath(cipherPath_);
} }
} }
}
} catch( rlog::Error &err ) catch (rlog::Error &err) {
{
rError("decode err: %s", err.message()); rError("decode err: %s", err.message());
err.log(_RLWarningChannel); err.log(_RLWarningChannel);
@ -386,22 +309,17 @@ DirNode::plainPath( const char *cipherPath_ )
} }
} }
string string DirNode::relativeCipherPath(const char *plaintextPath) {
DirNode::relativeCipherPath( const char *plaintextPath ) try {
{ if (plaintextPath[0] == '/') {
try
{
if(plaintextPath[0] == '/')
{
// mark with '+' to indicate special decoding.. // mark with '+' to indicate special decoding..
return string("+") + naming->encodeName(plaintextPath+1, return string("+") +
strlen(plaintextPath+1)); naming->encodeName(plaintextPath + 1, strlen(plaintextPath + 1));
} else } else {
{
return naming->encodePath(plaintextPath); return naming->encodePath(plaintextPath);
} }
} catch( rlog::Error &err ) }
{ catch (rlog::Error &err) {
rError("encode err: %s", err.message()); rError("encode err: %s", err.message());
err.log(_RLWarningChannel); err.log(_RLWarningChannel);
@ -409,29 +327,24 @@ DirNode::relativeCipherPath( const char *plaintextPath )
} }
} }
DirTraverse DirNode::openDir(const char *plaintextPath) DirTraverse DirNode::openDir(const char *plaintextPath) {
{
string cyName = rootDir + naming->encodePath(plaintextPath); string cyName = rootDir + naming->encodePath(plaintextPath);
// rDebug("openDir on %s", cyName.c_str() ); // rDebug("openDir on %s", cyName.c_str() );
DIR *dir = ::opendir(cyName.c_str()); DIR *dir = ::opendir(cyName.c_str());
if(dir == NULL) if (dir == NULL) {
{
rDebug("opendir error %s", strerror(errno)); rDebug("opendir error %s", strerror(errno));
return DirTraverse(shared_ptr<DIR>(), 0, shared_ptr<NameIO>()); return DirTraverse(shared_ptr<DIR>(), 0, shared_ptr<NameIO>());
} else } else {
{
shared_ptr<DIR> dp(dir, DirDeleter()); shared_ptr<DIR> dp(dir, DirDeleter());
uint64_t iv = 0; uint64_t iv = 0;
// if we're using chained IV mode, then compute the IV at this // if we're using chained IV mode, then compute the IV at this
// directory level.. // directory level..
try try {
{ if (naming->getChainedNameIV()) naming->encodePath(plaintextPath, &iv);
if( naming->getChainedNameIV() ) }
naming->encodePath( plaintextPath, &iv ); catch (rlog::Error &err) {
} catch( rlog::Error &err )
{
rError("encode err: %s", err.message()); rError("encode err: %s", err.message());
err.log(_RLWarningChannel); err.log(_RLWarningChannel);
} }
@ -439,9 +352,8 @@ DirTraverse DirNode::openDir(const char *plaintextPath)
} }
} }
bool DirNode::genRenameList( list<RenameEl> &renameList, bool DirNode::genRenameList(list<RenameEl> &renameList, const char *fromP,
const char *fromP, const char *toP ) const char *toP) {
{
uint64_t fromIV = 0, toIV = 0; uint64_t fromIV = 0, toIV = 0;
// compute the IV for both paths // compute the IV for both paths
@ -452,43 +364,37 @@ bool DirNode::genRenameList( list<RenameEl> &renameList,
string sourcePath = rootDir + fromCPart; string sourcePath = rootDir + fromCPart;
// ok..... we wish it was so simple.. should almost never happen // ok..... we wish it was so simple.. should almost never happen
if(fromIV == toIV) if (fromIV == toIV) return true;
return true;
// generate the real destination path, where we expect to find the files.. // generate the real destination path, where we expect to find the files..
rDebug("opendir %s", sourcePath.c_str()); rDebug("opendir %s", sourcePath.c_str());
shared_ptr<DIR> dir = shared_ptr<DIR>( shared_ptr<DIR> dir =
opendir( sourcePath.c_str() ), DirDeleter() ); shared_ptr<DIR>(opendir(sourcePath.c_str()), DirDeleter());
if(!dir) if (!dir) return false;
return false;
struct dirent *de = NULL; struct dirent *de = NULL;
while((de = ::readdir( dir.get() )) != NULL) while ((de = ::readdir(dir.get())) != NULL) {
{
// decode the name using the oldIV // decode the name using the oldIV
uint64_t localIV = fromIV; uint64_t localIV = fromIV;
string plainName; string plainName;
if ((de->d_name[0] == '.') && if ((de->d_name[0] == '.') &&
((de->d_name[1] == '\0') ((de->d_name[1] == '\0') ||
|| ((de->d_name[1] == '.') && (de->d_name[2] == '\0')))) ((de->d_name[1] == '.') && (de->d_name[2] == '\0')))) {
{
// skip "." and ".." // skip "." and ".."
continue; continue;
} }
try try {
{
plainName = naming->decodePath(de->d_name, &localIV); plainName = naming->decodePath(de->d_name, &localIV);
} catch( rlog::Error &ex ) }
{ catch (rlog::Error &ex) {
// if filename can't be decoded, then ignore it.. // if filename can't be decoded, then ignore it..
continue; continue;
} }
// any error in the following will trigger a rename failure. // any error in the following will trigger a rename failure.
try try {
{
// re-encode using the new IV.. // re-encode using the new IV..
localIV = toIV; localIV = toIV;
string newName = naming->encodePath(plainName.c_str(), &localIV); string newName = naming->encodePath(plainName.c_str(), &localIV);
@ -505,8 +411,7 @@ bool DirNode::genRenameList( list<RenameEl> &renameList,
bool isDir; bool isDir;
#if defined(_DIRENT_HAVE_D_TYPE) #if defined(_DIRENT_HAVE_D_TYPE)
if(de->d_type != DT_UNKNOWN) if (de->d_type != DT_UNKNOWN) {
{
isDir = (de->d_type == DT_DIR); isDir = (de->d_type == DT_DIR);
} else } else
#endif #endif
@ -516,25 +421,20 @@ bool DirNode::genRenameList( list<RenameEl> &renameList,
ren.isDirectory = isDir; ren.isDirectory = isDir;
if(isDir) if (isDir) {
{
// recurse.. We want to add subdirectory elements before the // recurse.. We want to add subdirectory elements before the
// parent, as that is the logical rename order.. // parent, as that is the logical rename order..
if(!genRenameList( renameList, if (!genRenameList(renameList, ren.oldPName.c_str(),
ren.oldPName.c_str(), ren.newPName.c_str())) {
ren.newPName.c_str()))
{
return false; return false;
} }
} }
rDebug("adding file %s to rename list", rDebug("adding file %s to rename list", oldFull.c_str());
oldFull.c_str());
renameList.push_back(ren); renameList.push_back(ren);
}
} catch( rlog::Error &err ) catch (rlog::Error &err) {
{
// We can't convert this name, because we don't have a valid IV for // We can't convert this name, because we don't have a valid IV for
// it (or perhaps a valid key).. It will be inaccessible.. // it (or perhaps a valid key).. It will be inaccessible..
rWarning("Aborting rename: error on file: %s", rWarning("Aborting rename: error on file: %s",
@ -550,7 +450,6 @@ bool DirNode::genRenameList( list<RenameEl> &renameList,
return true; return true;
} }
/* /*
A bit of a pain.. If a directory is renamed in a filesystem with A bit of a pain.. If a directory is renamed in a filesystem with
directory initialization vector chaining, then we have to recursively directory initialization vector chaining, then we have to recursively
@ -559,24 +458,19 @@ bool DirNode::genRenameList( list<RenameEl> &renameList,
Returns a list of renamed items on success, a null list on failure. Returns a list of renamed items on success, a null list on failure.
*/ */
shared_ptr<RenameOp> shared_ptr<RenameOp> DirNode::newRenameOp(const char *fromP, const char *toP) {
DirNode::newRenameOp( const char *fromP, const char *toP )
{
// Do the rename in two stages to avoid chasing our tail // Do the rename in two stages to avoid chasing our tail
// Undo everything if we encounter an error! // Undo everything if we encounter an error!
shared_ptr<list<RenameEl> > renameList(new list<RenameEl>); shared_ptr<list<RenameEl> > renameList(new list<RenameEl>);
if(!genRenameList( *renameList.get(), fromP, toP )) if (!genRenameList(*renameList.get(), fromP, toP)) {
{
rWarning("Error during generation of recursive rename list"); rWarning("Error during generation of recursive rename list");
return shared_ptr<RenameOp>(); return shared_ptr<RenameOp>();
} else } else
return shared_ptr<RenameOp>(new RenameOp(this, renameList)); return shared_ptr<RenameOp>(new RenameOp(this, renameList));
} }
int DirNode::mkdir(const char *plaintextPath, mode_t mode, uid_t uid,
int DirNode::mkdir(const char *plaintextPath, mode_t mode, gid_t gid) {
uid_t uid, gid_t gid)
{
string cyName = rootDir + naming->encodePath(plaintextPath); string cyName = rootDir + naming->encodePath(plaintextPath);
rAssert(!cyName.empty()); rAssert(!cyName.empty());
@ -585,23 +479,18 @@ int DirNode::mkdir(const char *plaintextPath, mode_t mode,
// if uid or gid are set, then that should be the directory owner // if uid or gid are set, then that should be the directory owner
int olduid = -1; int olduid = -1;
int oldgid = -1; int oldgid = -1;
if(uid != 0) if (uid != 0) olduid = setfsuid(uid);
olduid = setfsuid( uid ); if (gid != 0) oldgid = setfsgid(gid);
if(gid != 0)
oldgid = setfsgid( gid );
int res = ::mkdir(cyName.c_str(), mode); int res = ::mkdir(cyName.c_str(), mode);
if(olduid >= 0) if (olduid >= 0) setfsuid(olduid);
setfsuid( olduid ); if (oldgid >= 0) setfsgid(oldgid);
if(oldgid >= 0)
setfsgid( oldgid );
if(res == -1) if (res == -1) {
{
int eno = errno; int eno = errno;
rWarning("mkdir error on %s mode %i: %s", cyName.c_str(), rWarning("mkdir error on %s mode %i: %s", cyName.c_str(), mode,
mode, strerror(eno)); strerror(eno));
res = -eno; res = -eno;
} else } else
res = 0; res = 0;
@ -609,9 +498,7 @@ int DirNode::mkdir(const char *plaintextPath, mode_t mode,
return res; return res;
} }
int int DirNode::rename(const char *fromPlaintext, const char *toPlaintext) {
DirNode::rename( const char *fromPlaintext, const char *toPlaintext )
{
Lock _lock(mutex); Lock _lock(mutex);
string fromCName = rootDir + naming->encodePath(fromPlaintext); string fromCName = rootDir + naming->encodePath(fromPlaintext);
@ -624,15 +511,12 @@ DirNode::rename( const char *fromPlaintext, const char *toPlaintext )
shared_ptr<FileNode> toNode = findOrCreate(toPlaintext); shared_ptr<FileNode> toNode = findOrCreate(toPlaintext);
shared_ptr<RenameOp> renameOp; shared_ptr<RenameOp> renameOp;
if( hasDirectoryNameDependency() && isDirectory( fromCName.c_str() )) if (hasDirectoryNameDependency() && isDirectory(fromCName.c_str())) {
{
rLog(Info, "recursive rename begin"); rLog(Info, "recursive rename begin");
renameOp = newRenameOp(fromPlaintext, toPlaintext); renameOp = newRenameOp(fromPlaintext, toPlaintext);
if(!renameOp || !renameOp->apply()) if (!renameOp || !renameOp->apply()) {
{ if (renameOp) renameOp->undo();
if(renameOp)
renameOp->undo();
rWarning("rename aborted"); rWarning("rename aborted");
return -EACCES; return -EACCES;
@ -641,38 +525,33 @@ DirNode::rename( const char *fromPlaintext, const char *toPlaintext )
} }
int res = 0; int res = 0;
try try {
{
struct stat st; struct stat st;
bool preserve_mtime = ::stat(fromCName.c_str(), &st) == 0; bool preserve_mtime = ::stat(fromCName.c_str(), &st) == 0;
renameNode(fromPlaintext, toPlaintext); renameNode(fromPlaintext, toPlaintext);
res = ::rename(fromCName.c_str(), toCName.c_str()); res = ::rename(fromCName.c_str(), toCName.c_str());
if(res == -1) if (res == -1) {
{
// undo // undo
res = -errno; res = -errno;
renameNode(toPlaintext, fromPlaintext, false); renameNode(toPlaintext, fromPlaintext, false);
if(renameOp) if (renameOp) renameOp->undo();
renameOp->undo(); } else if (preserve_mtime) {
} else if(preserve_mtime)
{
struct utimbuf ut; struct utimbuf ut;
ut.actime = st.st_atime; ut.actime = st.st_atime;
ut.modtime = st.st_mtime; ut.modtime = st.st_mtime;
::utime(toCName.c_str(), &ut); ::utime(toCName.c_str(), &ut);
} }
} catch( rlog::Error &err ) }
{ catch (rlog::Error &err) {
// exception from renameNode, just show the error and continue.. // exception from renameNode, just show the error and continue..
err.log(_RLWarningChannel); err.log(_RLWarningChannel);
res = -EIO; res = -EIO;
} }
if(res != 0) if (res != 0) {
{
rLog(Info, "rename failed: %s", strerror(errno)); rLog(Info, "rename failed: %s", strerror(errno));
res = -errno; res = -errno;
} }
@ -680,8 +559,7 @@ DirNode::rename( const char *fromPlaintext, const char *toPlaintext )
return res; return res;
} }
int DirNode::link( const char *from, const char *to ) int DirNode::link(const char *from, const char *to) {
{
Lock _lock(mutex); Lock _lock(mutex);
string fromCName = rootDir + naming->encodePath(from); string fromCName = rootDir + naming->encodePath(from);
@ -693,11 +571,9 @@ int DirNode::link( const char *from, const char *to )
rLog(Info, "link %s -> %s", fromCName.c_str(), toCName.c_str()); rLog(Info, "link %s -> %s", fromCName.c_str(), toCName.c_str());
int res = -EPERM; int res = -EPERM;
if( fsConfig->config->externalIVChaining ) if (fsConfig->config->externalIVChaining) {
{
rLog(Info, "hard links not supported with external IV chaining!"); rLog(Info, "hard links not supported with external IV chaining!");
} else } else {
{
res = ::link(fromCName.c_str(), toCName.c_str()); res = ::link(fromCName.c_str(), toCName.c_str());
if (res == -1) if (res == -1)
res = -errno; res = -errno;
@ -712,30 +588,24 @@ int DirNode::link( const char *from, const char *to )
The node is keyed by filename, so a rename means the internal node names The node is keyed by filename, so a rename means the internal node names
must be changed. must be changed.
*/ */
shared_ptr<FileNode> DirNode::renameNode( const char *from, const char *to ) shared_ptr<FileNode> DirNode::renameNode(const char *from, const char *to) {
{
return renameNode(from, to, true); return renameNode(from, to, true);
} }
shared_ptr<FileNode> DirNode::renameNode(const char *from, const char *to, shared_ptr<FileNode> DirNode::renameNode(const char *from, const char *to,
bool forwardMode ) bool forwardMode) {
{
shared_ptr<FileNode> node = findOrCreate(from); shared_ptr<FileNode> node = findOrCreate(from);
if(node) if (node) {
{
uint64_t newIV = 0; uint64_t newIV = 0;
string cname = rootDir + naming->encodePath(to, &newIV); string cname = rootDir + naming->encodePath(to, &newIV);
rLog(Info, "renaming internal node %s -> %s", rLog(Info, "renaming internal node %s -> %s", node->cipherName(),
node->cipherName(), cname.c_str()); cname.c_str());
if(node->setName( to, cname.c_str(), newIV, forwardMode )) if (node->setName(to, cname.c_str(), newIV, forwardMode)) {
{ if (ctx) ctx->renameNode(from, to);
if(ctx) } else {
ctx->renameNode( from, to );
} else
{
// rename error! - put it back // rename error! - put it back
rError("renameNode failed"); rError("renameNode failed");
throw ERROR("Internal node name change failed!"); throw ERROR("Internal node name change failed!");
@ -745,22 +615,17 @@ shared_ptr<FileNode> DirNode::renameNode( const char *from, const char *to,
return node; return node;
} }
shared_ptr<FileNode> DirNode::findOrCreate( const char *plainName) shared_ptr<FileNode> DirNode::findOrCreate(const char *plainName) {
{
shared_ptr<FileNode> node; shared_ptr<FileNode> node;
if(ctx) if (ctx) node = ctx->lookupNode(plainName);
node = ctx->lookupNode( plainName );
if(!node) if (!node) {
{
uint64_t iv = 0; uint64_t iv = 0;
string cipherName = naming->encodePath(plainName, &iv); string cipherName = naming->encodePath(plainName, &iv);
node.reset( new FileNode( this, fsConfig, node.reset(new FileNode(this, fsConfig, plainName,
plainName,
(rootDir + cipherName).c_str())); (rootDir + cipherName).c_str()));
if(fsConfig->config->externalIVChaining) if (fsConfig->config->externalIVChaining) node->setName(0, 0, iv);
node->setName(0, 0, iv);
rLog(Info, "created FileNode for %s", node->cipherName()); rLog(Info, "created FileNode for %s", node->cipherName());
} }
@ -768,9 +633,8 @@ shared_ptr<FileNode> DirNode::findOrCreate( const char *plainName)
return node; return node;
} }
shared_ptr<FileNode> shared_ptr<FileNode> DirNode::lookupNode(const char *plainName,
DirNode::lookupNode( const char *plainName, const char * requestor ) const char *requestor) {
{
(void)requestor; (void)requestor;
Lock _lock(mutex); Lock _lock(mutex);
@ -784,10 +648,9 @@ DirNode::lookupNode( const char *plainName, const char * requestor )
node on sucess.. This is done in one step to avoid any race conditions node on sucess.. This is done in one step to avoid any race conditions
with the stored state of the file. with the stored state of the file.
*/ */
shared_ptr<FileNode> shared_ptr<FileNode> DirNode::openNode(const char *plainName,
DirNode::openNode( const char *plainName, const char * requestor, int flags, const char *requestor, int flags,
int *result ) int *result) {
{
(void)requestor; (void)requestor;
rAssert(result != NULL); rAssert(result != NULL);
Lock _lock(mutex); Lock _lock(mutex);
@ -800,28 +663,26 @@ DirNode::openNode( const char *plainName, const char * requestor, int flags,
return shared_ptr<FileNode>(); return shared_ptr<FileNode>();
} }
int DirNode::unlink( const char *plaintextName ) int DirNode::unlink(const char *plaintextName) {
{
string cyName = naming->encodePath(plaintextName); string cyName = naming->encodePath(plaintextName);
rLog(Info, "unlink %s", cyName.c_str()); rLog(Info, "unlink %s", cyName.c_str());
Lock _lock(mutex); Lock _lock(mutex);
int res = 0; int res = 0;
if(ctx && ctx->lookupNode( plaintextName )) if (ctx && ctx->lookupNode(plaintextName)) {
{
// If FUSE is running with "hard_remove" option where it doesn't // If FUSE is running with "hard_remove" option where it doesn't
// hide open files for us, then we can't allow an unlink of an open // hide open files for us, then we can't allow an unlink of an open
// file.. // file..
rWarning("Refusing to unlink open file: %s, hard_remove option " rWarning(
"is probably in effect", cyName.c_str() ); "Refusing to unlink open file: %s, hard_remove option "
"is probably in effect",
cyName.c_str());
res = -EBUSY; res = -EBUSY;
} else } else {
{
string fullName = rootDir + cyName; string fullName = rootDir + cyName;
res = ::unlink(fullName.c_str()); res = ::unlink(fullName.c_str());
if(res == -1) if (res == -1) {
{
res = -errno; res = -errno;
rDebug("unlink error: %s", strerror(errno)); rDebug("unlink error: %s", strerror(errno));
} }

View File

@ -40,8 +40,7 @@ class RenameOp;
struct RenameEl; struct RenameEl;
class EncFS_Context; class EncFS_Context;
class DirTraverse class DirTraverse {
{
public: public:
DirTraverse(const shared_ptr<DIR> &dirPtr, uint64_t iv, DirTraverse(const shared_ptr<DIR> &dirPtr, uint64_t iv,
const shared_ptr<NameIO> &naming); const shared_ptr<NameIO> &naming);
@ -63,8 +62,8 @@ public:
The opposite of nextPlaintextName(), as that skips undecodable names.. The opposite of nextPlaintextName(), as that skips undecodable names..
*/ */
std::string nextInvalid(); std::string nextInvalid();
private:
private:
shared_ptr<DIR> dir; // struct DIR shared_ptr<DIR> dir; // struct DIR
// initialization vector to use. Not very general purpose, but makes it // initialization vector to use. Not very general purpose, but makes it
// more efficient to support filename IV chaining.. // more efficient to support filename IV chaining..
@ -74,24 +73,20 @@ private:
inline bool DirTraverse::valid() const { return dir.get() != 0; } inline bool DirTraverse::valid() const { return dir.get() != 0; }
#ifdef USE_HASHMAP #ifdef USE_HASHMAP
namespace __gnu_cxx namespace __gnu_cxx {
{ template <>
template<> struct hash<std::string> struct hash<std::string> {
{ size_t operator()(const std::string &__s) const {
size_t operator() (const std::string &__s) const
{
return __stl_hash_string(__s.c_str()); return __stl_hash_string(__s.c_str());
} }
}; };
} }
#endif #endif
class DirNode class DirNode {
{
public: public:
// sourceDir points to where raw files are stored // sourceDir points to where raw files are stored
DirNode(EncFS_Context *ctx, DirNode(EncFS_Context *ctx, const std::string &sourceDir,
const std::string &sourceDir,
const FSConfigPtr &config); const FSConfigPtr &config);
~DirNode(); ~DirNode();
@ -107,7 +102,8 @@ public:
node is not retained. If the open succeeds, then the node is returned. node is not retained. If the open succeeds, then the node is returned.
*/ */
shared_ptr<FileNode> openNode(const char *plaintextName, shared_ptr<FileNode> openNode(const char *plaintextName,
const char *requestor, int flags, int *openResult ); const char *requestor, int flags,
int *openResult);
std::string cipherPath(const char *plaintextPath); std::string cipherPath(const char *plaintextPath);
std::string cipherPathWithoutRoot(const char *plaintextPath); std::string cipherPathWithoutRoot(const char *plaintextPath);
@ -132,8 +128,8 @@ public:
DirTraverse openDir(const char *plainDirName); DirTraverse openDir(const char *plainDirName);
// uid and gid are used as the directory owner, only if not zero // uid and gid are used as the directory owner, only if not zero
int mkdir( const char *plaintextPath, mode_t mode, int mkdir(const char *plaintextPath, mode_t mode, uid_t uid = 0,
uid_t uid = 0, gid_t gid = 0); gid_t gid = 0);
int rename(const char *fromPlaintext, const char *toPlaintext); int rename(const char *fromPlaintext, const char *toPlaintext);
@ -143,7 +139,6 @@ public:
int idleSeconds(); int idleSeconds();
protected: protected:
/* /*
notify that a file is being renamed. notify that a file is being renamed.
This renames the internal node, if any. If the file is not open, then This renames the internal node, if any. If the file is not open, then
@ -163,7 +158,6 @@ protected:
shared_ptr<RenameOp> newRenameOp(const char *from, const char *to); shared_ptr<RenameOp> newRenameOp(const char *from, const char *to);
private: private:
friend class RenameOp; friend class RenameOp;
bool genRenameList(std::list<RenameEl> &list, const char *fromP, bool genRenameList(std::list<RenameEl> &list, const char *fromP,

View File

@ -28,8 +28,7 @@
#include "CipherKey.h" #include "CipherKey.h"
#include "shared_ptr.h" #include "shared_ptr.h"
enum ConfigType enum ConfigType {
{
Config_None = 0, Config_None = 0,
Config_Prehistoric, Config_Prehistoric,
Config_V3, Config_V3,
@ -42,8 +41,7 @@ struct EncFS_Opts;
class Cipher; class Cipher;
class NameIO; class NameIO;
struct EncFSConfig struct EncFSConfig {
{
ConfigType cfgType; ConfigType cfgType;
std::string creator; std::string creator;
@ -71,10 +69,7 @@ struct EncFSConfig
bool chainedNameIV; // filename IV chaining bool chainedNameIV; // filename IV chaining
bool allowHoles; // allow holes in files (implicit zero blocks) bool allowHoles; // allow holes in files (implicit zero blocks)
EncFSConfig() EncFSConfig() : keyData(), salt() {
: keyData()
, salt()
{
cfgType = Config_None; cfgType = Config_None;
subVersion = 0; subVersion = 0;
blockMACBytes = 0; blockMACBytes = 0;
@ -111,8 +106,7 @@ private:
std::ostream &operator<<(std::ostream &os, const EncFSConfig &cfg); std::ostream &operator<<(std::ostream &os, const EncFSConfig &cfg);
std::istream &operator>>(std::istream &os, EncFSConfig &cfg); std::istream &operator>>(std::istream &os, EncFSConfig &cfg);
struct FSConfig struct FSConfig {
{
shared_ptr<EncFSConfig> config; shared_ptr<EncFSConfig> config;
shared_ptr<EncFS_Opts> opts; shared_ptr<EncFS_Opts> opts;
@ -129,4 +123,3 @@ struct FSConfig
typedef shared_ptr<FSConfig> FSConfigPtr; typedef shared_ptr<FSConfig> FSConfigPtr;
#endif #endif

View File

@ -20,22 +20,13 @@
#include "FileIO.h" #include "FileIO.h"
FileIO::FileIO() FileIO::FileIO() {}
{
}
FileIO::~FileIO() FileIO::~FileIO() {}
{
}
int FileIO::blockSize() const int FileIO::blockSize() const { return 1; }
{
return 1;
}
bool FileIO::setIV( uint64_t iv ) bool FileIO::setIV(uint64_t iv) {
{
(void)iv; (void)iv;
return true; return true;
} }

View File

@ -27,8 +27,7 @@
#include "Interface.h" #include "Interface.h"
struct IORequest struct IORequest {
{
off_t offset; off_t offset;
// amount of bytes to read/write. // amount of bytes to read/write.
@ -38,15 +37,9 @@ struct IORequest
IORequest(); IORequest();
}; };
inline IORequest::IORequest() inline IORequest::IORequest() : offset(0), dataLen(0), data(0) {}
: offset(0)
, dataLen(0)
, data(0)
{
}
class FileIO class FileIO {
{
public: public:
FileIO(); FileIO();
virtual ~FileIO(); virtual ~FileIO();
@ -77,6 +70,7 @@ public:
virtual int truncate(off_t size) = 0; virtual int truncate(off_t size) = 0;
virtual bool isWritable() const = 0; virtual bool isWritable() const = 0;
private: private:
// not implemented.. // not implemented..
FileIO(const FileIO &); FileIO(const FileIO &);
@ -84,4 +78,3 @@ private:
}; };
#endif #endif

View File

@ -66,8 +66,7 @@ using namespace rlog;
static RLogChannel *Info = DEF_CHANNEL("info/FileNode", Log_Info); static RLogChannel *Info = DEF_CHANNEL("info/FileNode", Log_Info);
FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg, FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg,
const char *plaintextName_, const char *cipherName_) const char *plaintextName_, const char *cipherName_) {
{
pthread_mutex_init(&mutex, 0); pthread_mutex_init(&mutex, 0);
Lock _lock(mutex); Lock _lock(mutex);
@ -86,8 +85,7 @@ FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg,
io = shared_ptr<FileIO>(new MACFileIO(io, fsConfig)); io = shared_ptr<FileIO>(new MACFileIO(io, fsConfig));
} }
FileNode::~FileNode() FileNode::~FileNode() {
{
// FileNode mutex should be locked before the destructor is called // FileNode mutex should be locked before the destructor is called
// pthread_mutex_lock( &mutex ); // pthread_mutex_lock( &mutex );
@ -98,23 +96,13 @@ FileNode::~FileNode()
pthread_mutex_destroy(&mutex); pthread_mutex_destroy(&mutex);
} }
const char *FileNode::cipherName() const const char *FileNode::cipherName() const { return _cname.c_str(); }
{
return _cname.c_str();
}
const char *FileNode::plaintextName() const const char *FileNode::plaintextName() const { return _pname.c_str(); }
{
return _pname.c_str();
}
string FileNode::plaintextParent() const string FileNode::plaintextParent() const { return parentDirectory(_pname); }
{
return parentDirectory( _pname );
}
static bool setIV(const shared_ptr<FileIO> &io, uint64_t iv) static bool setIV(const shared_ptr<FileIO> &io, uint64_t iv) {
{
struct stat stbuf; struct stat stbuf;
if ((io->getAttr(&stbuf) < 0) || S_ISREG(stbuf.st_mode)) if ((io->getAttr(&stbuf) < 0) || S_ISREG(stbuf.st_mode))
return io->setIV(iv); return io->setIV(iv);
@ -123,38 +111,29 @@ static bool setIV(const shared_ptr<FileIO> &io, uint64_t iv)
} }
bool FileNode::setName(const char *plaintextName_, const char *cipherName_, bool FileNode::setName(const char *plaintextName_, const char *cipherName_,
uint64_t iv, bool setIVFirst ) uint64_t iv, bool setIVFirst) {
{
// Lock _lock( mutex ); // Lock _lock( mutex );
rDebug("calling setIV on %s", cipherName_); rDebug("calling setIV on %s", cipherName_);
if(setIVFirst) if (setIVFirst) {
{ if (fsConfig->config->externalIVChaining && !setIV(io, iv)) return false;
if(fsConfig->config->externalIVChaining && !setIV(io, iv))
return false;
// now change the name.. // now change the name..
if(plaintextName_) if (plaintextName_) this->_pname = plaintextName_;
this->_pname = plaintextName_; if (cipherName_) {
if(cipherName_)
{
this->_cname = cipherName_; this->_cname = cipherName_;
io->setFileName(cipherName_); io->setFileName(cipherName_);
} }
} else } else {
{
std::string oldPName = _pname; std::string oldPName = _pname;
std::string oldCName = _cname; std::string oldCName = _cname;
if(plaintextName_) if (plaintextName_) this->_pname = plaintextName_;
this->_pname = plaintextName_; if (cipherName_) {
if(cipherName_)
{
this->_cname = cipherName_; this->_cname = cipherName_;
io->setFileName(cipherName_); io->setFileName(cipherName_);
} }
if(fsConfig->config->externalIVChaining && !setIV(io, iv)) if (fsConfig->config->externalIVChaining && !setIV(io, iv)) {
{
_pname = oldPName; _pname = oldPName;
_cname = oldCName; _cname = oldCName;
return false; return false;
@ -164,27 +143,22 @@ bool FileNode::setName( const char *plaintextName_, const char *cipherName_,
return true; return true;
} }
int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid) int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid) {
{
Lock _lock(mutex); Lock _lock(mutex);
int res; int res;
int olduid = -1; int olduid = -1;
int oldgid = -1; int oldgid = -1;
if(uid != 0) if (uid != 0) {
{
olduid = setfsuid(uid); olduid = setfsuid(uid);
if(olduid == -1) if (olduid == -1) {
{
rInfo("setfsuid error: %s", strerror(errno)); rInfo("setfsuid error: %s", strerror(errno));
return -EPERM; return -EPERM;
} }
} }
if(gid != 0) if (gid != 0) {
{
oldgid = setfsgid(gid); oldgid = setfsgid(gid);
if(oldgid == -1) if (oldgid == -1) {
{
rInfo("setfsgid error: %s", strerror(errno)); rInfo("setfsgid error: %s", strerror(errno));
return -EPERM; return -EPERM;
} }
@ -197,20 +171,16 @@ int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid)
*/ */
if (S_ISREG(mode)) { if (S_ISREG(mode)) {
res = ::open(_cname.c_str(), O_CREAT | O_EXCL | O_WRONLY, mode); res = ::open(_cname.c_str(), O_CREAT | O_EXCL | O_WRONLY, mode);
if (res >= 0) if (res >= 0) res = ::close(res);
res = ::close( res );
} else if (S_ISFIFO(mode)) } else if (S_ISFIFO(mode))
res = ::mkfifo(_cname.c_str(), mode); res = ::mkfifo(_cname.c_str(), mode);
else else
res = ::mknod(_cname.c_str(), mode, rdev); res = ::mknod(_cname.c_str(), mode, rdev);
if(olduid >= 0) if (olduid >= 0) setfsuid(olduid);
setfsuid( olduid ); if (oldgid >= 0) setfsgid(oldgid);
if(oldgid >= 0)
setfsgid( oldgid );
if(res == -1) if (res == -1) {
{
int eno = errno; int eno = errno;
rDebug("mknod error: %s", strerror(eno)); rDebug("mknod error: %s", strerror(eno));
res = -eno; res = -eno;
@ -219,32 +189,28 @@ int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid)
return res; return res;
} }
int FileNode::open(int flags) const int FileNode::open(int flags) const {
{
Lock _lock(mutex); Lock _lock(mutex);
int res = io->open(flags); int res = io->open(flags);
return res; return res;
} }
int FileNode::getAttr(struct stat *stbuf) const int FileNode::getAttr(struct stat *stbuf) const {
{
Lock _lock(mutex); Lock _lock(mutex);
int res = io->getAttr(stbuf); int res = io->getAttr(stbuf);
return res; return res;
} }
off_t FileNode::getSize() const off_t FileNode::getSize() const {
{
Lock _lock(mutex); Lock _lock(mutex);
int res = io->getSize(); int res = io->getSize();
return res; return res;
} }
ssize_t FileNode::read( off_t offset, unsigned char *data, ssize_t size ) const ssize_t FileNode::read(off_t offset, unsigned char *data, ssize_t size) const {
{
IORequest req; IORequest req;
req.offset = offset; req.offset = offset;
req.dataLen = size; req.dataLen = size;
@ -255,10 +221,9 @@ ssize_t FileNode::read( off_t offset, unsigned char *data, ssize_t size ) const
return io->read(req); return io->read(req);
} }
bool FileNode::write(off_t offset, unsigned char *data, ssize_t size) bool FileNode::write(off_t offset, unsigned char *data, ssize_t size) {
{ rLog(Info, "FileNode::write offset %" PRIi64 ", data size %i", offset,
rLog(Info, "FileNode::write offset %" PRIi64 ", data size %i", (int)size);
offset, (int)size);
IORequest req; IORequest req;
req.offset = offset; req.offset = offset;
@ -270,20 +235,17 @@ bool FileNode::write(off_t offset, unsigned char *data, ssize_t size)
return io->write(req); return io->write(req);
} }
int FileNode::truncate( off_t size ) int FileNode::truncate(off_t size) {
{
Lock _lock(mutex); Lock _lock(mutex);
return io->truncate(size); return io->truncate(size);
} }
int FileNode::sync(bool datasync) int FileNode::sync(bool datasync) {
{
Lock _lock(mutex); Lock _lock(mutex);
int fh = io->open(O_RDONLY); int fh = io->open(O_RDONLY);
if(fh >= 0) if (fh >= 0) {
{
int res = -EIO; int res = -EIO;
#ifdef linux #ifdef linux
if (datasync) if (datasync)
@ -297,11 +259,9 @@ int FileNode::sync(bool datasync)
res = fsync(fh); res = fsync(fh);
#endif #endif
if(res == -1) if (res == -1) res = -errno;
res = -errno;
return res; return res;
} else } else
return fh; return fh;
} }

View File

@ -33,12 +33,9 @@ class Cipher;
class FileIO; class FileIO;
class DirNode; class DirNode;
class FileNode class FileNode {
{
public: public:
FileNode(DirNode *parent, FileNode(DirNode *parent, const FSConfigPtr &cfg, const char *plaintextName,
const FSConfigPtr &cfg,
const char *plaintextName,
const char *cipherName); const char *cipherName);
~FileNode(); ~FileNode();
@ -50,8 +47,8 @@ public:
// if setIVFirst is true, then the IV is changed before the name is changed // if setIVFirst is true, then the IV is changed before the name is changed
// (default). The reverse is also supported for special cases.. // (default). The reverse is also supported for special cases..
bool setName( const char *plaintextName, const char *cipherName, bool setName(const char *plaintextName, const char *cipherName, uint64_t iv,
uint64_t iv, bool setIVFirst = true); bool setIVFirst = true);
// create node // create node
// If uid/gid are not 0, then chown is used change ownership as specified // If uid/gid are not 0, then chown is used change ownership as specified
@ -72,8 +69,8 @@ public:
// datasync or full sync // datasync or full sync
int sync(bool dataSync); int sync(bool dataSync);
private:
private:
// doing locking at the FileNode level isn't as efficient as at the // doing locking at the FileNode level isn't as efficient as at the
// lowest level of RawFileIO, since that means locks are held longer // lowest level of RawFileIO, since that means locks are held longer
// (held during CPU intensive crypto operations!). However it makes it // (held during CPU intensive crypto operations!). However it makes it
@ -92,9 +89,6 @@ private:
private: private:
FileNode(const FileNode &src); FileNode(const FileNode &src);
FileNode &operator=(const FileNode &src); FileNode &operator=(const FileNode &src);
}; };
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -45,8 +45,7 @@ bool userAllowMkdir(int promptno, const char *dirPath, mode_t mode );
class Cipher; class Cipher;
class DirNode; class DirNode;
struct EncFS_Root struct EncFS_Root {
{
shared_ptr<Cipher> cipher; shared_ptr<Cipher> cipher;
CipherKey volumeKey; CipherKey volumeKey;
shared_ptr<DirNode> root; shared_ptr<DirNode> root;
@ -57,15 +56,9 @@ struct EncFS_Root
typedef shared_ptr<EncFS_Root> RootPtr; typedef shared_ptr<EncFS_Root> RootPtr;
enum ConfigMode enum ConfigMode { Config_Prompt, Config_Standard, Config_Paranoia };
{
Config_Prompt,
Config_Standard,
Config_Paranoia
};
struct EncFS_Opts struct EncFS_Opts {
{
std::string rootDir; std::string rootDir;
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
@ -85,8 +78,7 @@ struct EncFS_Opts
ConfigMode configMode; ConfigMode configMode;
EncFS_Opts() EncFS_Opts() {
{
createIfNotFound = true; createIfNotFound = true;
idleTracking = false; idleTracking = false;
mountOnDemand = false; mountOnDemand = false;
@ -118,25 +110,21 @@ class EncFS_Context;
RootPtr initFS(EncFS_Context *ctx, const shared_ptr<EncFS_Opts> &opts); RootPtr initFS(EncFS_Context *ctx, const shared_ptr<EncFS_Opts> &opts);
RootPtr createV6Config( EncFS_Context *ctx, RootPtr createV6Config(EncFS_Context *ctx, const shared_ptr<EncFS_Opts> &opts);
const shared_ptr<EncFS_Opts> &opts );
void showFSInfo(const shared_ptr<EncFSConfig> &config); void showFSInfo(const shared_ptr<EncFSConfig> &config);
bool readV4Config( const char *configFile, bool readV4Config(const char *configFile, const shared_ptr<EncFSConfig> &config,
const shared_ptr<EncFSConfig> &config,
struct ConfigInfo *); struct ConfigInfo *);
bool writeV4Config(const char *configFile, bool writeV4Config(const char *configFile,
const shared_ptr<EncFSConfig> &config); const shared_ptr<EncFSConfig> &config);
bool readV5Config( const char *configFile, bool readV5Config(const char *configFile, const shared_ptr<EncFSConfig> &config,
const shared_ptr<EncFSConfig> &config,
struct ConfigInfo *); struct ConfigInfo *);
bool writeV5Config(const char *configFile, bool writeV5Config(const char *configFile,
const shared_ptr<EncFSConfig> &config); const shared_ptr<EncFSConfig> &config);
bool readV6Config( const char *configFile, bool readV6Config(const char *configFile, const shared_ptr<EncFSConfig> &config,
const shared_ptr<EncFSConfig> &config,
struct ConfigInfo *); struct ConfigInfo *);
bool writeV6Config(const char *configFile, bool writeV6Config(const char *configFile,
const shared_ptr<EncFSConfig> &config); const shared_ptr<EncFSConfig> &config);

View File

@ -31,39 +31,21 @@ using namespace rlog;
static RLogChannel *Info = DEF_CHANNEL("info/iface", Log_Info); static RLogChannel *Info = DEF_CHANNEL("info/iface", Log_Info);
Interface::Interface(const char *name_, int Current, int Revision, int Age) Interface::Interface(const char *name_, int Current, int Revision, int Age)
: _name( name_ ) : _name(name_), _current(Current), _revision(Revision), _age(Age) {}
, _current( Current )
, _revision( Revision )
, _age( Age )
{
}
Interface::Interface(const std::string &name_, int Current, Interface::Interface(const std::string &name_, int Current, int Revision,
int Revision, int Age) int Age)
: _name( name_ ) : _name(name_), _current(Current), _revision(Revision), _age(Age) {}
, _current( Current )
, _revision( Revision )
, _age( Age )
{
}
Interface::Interface(const Interface &src) Interface::Interface(const Interface &src)
: _name( src._name ) : _name(src._name),
, _current( src._current ) _current(src._current),
, _revision( src._revision ) _revision(src._revision),
, _age( src._age ) _age(src._age) {}
{
}
Interface::Interface() Interface::Interface() : _current(0), _revision(0), _age(0) {}
: _current( 0 )
, _revision( 0 )
, _age( 0 )
{
}
Interface &Interface::operator = (const Interface &src) Interface &Interface::operator=(const Interface &src) {
{
_name = src._name; _name = src._name;
_current = src._current; _current = src._current;
_revision = src._revision; _revision = src._revision;
@ -71,60 +53,30 @@ Interface &Interface::operator = (const Interface &src)
return *this; return *this;
} }
const std::string & Interface::name() const const std::string &Interface::name() const { return _name; }
{
return _name; std::string &Interface::name() { return _name; }
int Interface::current() const { return _current; }
int &Interface::current() { return _current; }
int Interface::revision() const { return _revision; }
int &Interface::revision() { return _revision; }
int Interface::age() const { return _age; }
int &Interface::age() { return _age; }
bool operator==(const Interface &A, const Interface &B) {
return (A.name() == B.name() && A.current() == B.current() &&
A.revision() == B.revision() && A.age() == B.age());
} }
std::string & Interface::name() bool operator!=(const Interface &A, const Interface &B) {
{ return (A.name() != B.name() || A.current() != B.current() ||
return _name; A.revision() != B.revision() || A.age() != B.age());
}
int Interface::current() const
{
return _current;
}
int &Interface::current()
{
return _current;
}
int Interface::revision() const
{
return _revision;
}
int &Interface::revision()
{
return _revision;
}
int Interface::age() const
{
return _age;
}
int &Interface::age()
{
return _age;
}
bool operator == (const Interface &A, const Interface &B)
{
return ( A.name() == B.name()
&& A.current() == B.current()
&& A.revision() == B.revision()
&& A.age() == B.age() );
}
bool operator != (const Interface &A, const Interface &B)
{
return ( A.name() != B.name()
|| A.current() != B.current()
|| A.revision() != B.revision()
|| A.age() != B.age() );
} }
// zero branch method of getting comparison sign.. // zero branch method of getting comparison sign..
@ -139,8 +91,7 @@ static int sign( int a, int b )
} }
#else #else
// simple, easy to check, unlikely to break due to unforseen events.. // simple, easy to check, unlikely to break due to unforseen events..
static int sign( int a, int b ) static int sign(int a, int b) {
{
if (a < b) if (a < b)
return 0; return 0;
else if (a == b) else if (a == b)
@ -150,8 +101,7 @@ static int sign( int a, int b )
} }
#endif #endif
static int diffSum( const Interface &A, const Interface &B ) static int diffSum(const Interface &A, const Interface &B) {
{
int cS = sign(A.current(), B.current()); int cS = sign(A.current(), B.current());
int aS = sign(A.age(), B.age()); int aS = sign(A.age(), B.age());
int rS = sign(A.revision(), B.revision()); int rS = sign(A.revision(), B.revision());
@ -161,69 +111,54 @@ static int diffSum( const Interface &A, const Interface &B )
const int EqualVersion = (1 * 3 + 1) * 3 + 1; const int EqualVersion = (1 * 3 + 1) * 3 + 1;
bool Interface::implements(const Interface &B) const bool Interface::implements(const Interface &B) const {
{ rLog(Info, "checking if %s(%i:%i:%i) implements %s(%i:%i:%i)", name().c_str(),
rLog(Info, "checking if %s(%i:%i:%i) implements %s(%i:%i:%i)", current(), revision(), age(), B.name().c_str(), B.current(),
name().c_str(), current(), revision(), age(), B.revision(), B.age());
B.name().c_str(), B.current(), B.revision(), B.age());
if( name() != B.name() ) if (name() != B.name()) return false;
return false;
int currentDiff = current() - B.current(); int currentDiff = current() - B.current();
return (currentDiff >= 0 && currentDiff <= age()); return (currentDiff >= 0 && currentDiff <= age());
} }
bool operator<(const Interface &A, const Interface &B) {
bool operator < (const Interface &A, const Interface &B) if (A.name() == B.name()) {
{
if( A.name() == B.name() )
{
return (diffSum(A, B) < EqualVersion); return (diffSum(A, B) < EqualVersion);
} else } else
return A.name() < B.name(); return A.name() < B.name();
} }
bool operator > (const Interface &A, const Interface &B) bool operator>(const Interface &A, const Interface &B) {
{ if (A.name() == B.name()) {
if( A.name() == B.name() )
{
return (diffSum(A, B) > EqualVersion); return (diffSum(A, B) > EqualVersion);
} else } else
return A.name() < B.name(); return A.name() < B.name();
} }
bool operator <= (const Interface &A, const Interface &B) bool operator<=(const Interface &A, const Interface &B) {
{ if (A.name() == B.name()) {
if( A.name() == B.name() )
{
return (diffSum(A, B) <= EqualVersion); return (diffSum(A, B) <= EqualVersion);
} else } else
return A.name() < B.name(); return A.name() < B.name();
} }
bool operator >= (const Interface &A, const Interface &B) bool operator>=(const Interface &A, const Interface &B) {
{ if (A.name() == B.name()) {
if( A.name() == B.name() )
{
return (diffSum(A, B) >= EqualVersion); return (diffSum(A, B) >= EqualVersion);
} else } else
return A.name() < B.name(); return A.name() < B.name();
} }
ConfigVar &operator<<(ConfigVar &dst, const rel::Interface &iface) {
ConfigVar & operator << (ConfigVar &dst, const rel::Interface &iface)
{
dst << iface.name() << iface.current() << iface.revision() << iface.age(); dst << iface.name() << iface.current() << iface.revision() << iface.age();
return dst; return dst;
} }
const ConfigVar & operator >> (const ConfigVar &src, Interface &iface) const ConfigVar &operator>>(const ConfigVar &src, Interface &iface) {
{
src >> iface.name(); src >> iface.name();
src >> iface.current(); src >> iface.current();
src >> iface.revision(); src >> iface.revision();
src >> iface.age(); src >> iface.age();
return src; return src;
} }

View File

@ -26,13 +26,10 @@
class ConfigVar; class ConfigVar;
// part of REL library.. // part of REL library..
namespace rel namespace rel {
{
class Interface class Interface {
{
public: public:
/*! /*!
Version numbers as described by libtool: info://libtool/versioning Version numbers as described by libtool: info://libtool/versioning
Current - the most recent interface api that is implemented. Current - the most recent interface api that is implemented.
@ -70,7 +67,6 @@ namespace rel
int _revision; int _revision;
int _age; int _age;
}; };
} }
ConfigVar &operator<<(ConfigVar &, const rel::Interface &); ConfigVar &operator<<(ConfigVar &, const rel::Interface &);
@ -84,4 +80,3 @@ bool operator == (const rel::Interface &A, const rel::Interface &B);
bool operator!=(const rel::Interface &A, const rel::Interface &B); bool operator!=(const rel::Interface &A, const rel::Interface &B);
#endif #endif

View File

@ -51,62 +51,41 @@ static RLogChannel *Info = DEF_CHANNEL("info/MACFileIO", Log_Info);
// //
static rel::Interface MACFileIO_iface("FileIO/MAC", 2, 1, 0); static rel::Interface MACFileIO_iface("FileIO/MAC", 2, 1, 0);
int dataBlockSize(const FSConfigPtr &cfg) int dataBlockSize(const FSConfigPtr &cfg) {
{ return cfg->config->blockSize - cfg->config->blockMACBytes -
return cfg->config->blockSize cfg->config->blockMACRandBytes;
- cfg->config->blockMACBytes
- cfg->config->blockMACRandBytes;
} }
MACFileIO::MACFileIO( const shared_ptr<FileIO> &_base, MACFileIO::MACFileIO(const shared_ptr<FileIO> &_base, const FSConfigPtr &cfg)
const FSConfigPtr &cfg ) : BlockFileIO(dataBlockSize(cfg), cfg),
: BlockFileIO( dataBlockSize( cfg ), cfg ) base(_base),
, base( _base ) cipher(cfg->cipher),
, cipher( cfg->cipher ) key(cfg->key),
, key( cfg->key ) macBytes(cfg->config->blockMACBytes),
, macBytes( cfg->config->blockMACBytes ) randBytes(cfg->config->blockMACRandBytes),
, randBytes( cfg->config->blockMACRandBytes ) warnOnly(cfg->opts->forceDecode) {
, warnOnly( cfg->opts->forceDecode )
{
rAssert(macBytes >= 0 && macBytes <= 8); rAssert(macBytes >= 0 && macBytes <= 8);
rAssert(randBytes >= 0); rAssert(randBytes >= 0);
rLog(Info, "fs block size = %i, macBytes = %i, randBytes = %i", rLog(Info, "fs block size = %i, macBytes = %i, randBytes = %i",
cfg->config->blockSize, cfg->config->blockSize, cfg->config->blockMACBytes,
cfg->config->blockMACBytes,
cfg->config->blockMACRandBytes); cfg->config->blockMACRandBytes);
} }
MACFileIO::~MACFileIO() MACFileIO::~MACFileIO() {}
{
}
rel::Interface MACFileIO::interface() const rel::Interface MACFileIO::interface() const { return MACFileIO_iface; }
{
return MACFileIO_iface;
}
int MACFileIO::open( int flags ) int MACFileIO::open(int flags) { return base->open(flags); }
{
return base->open( flags );
}
void MACFileIO::setFileName( const char *fileName ) void MACFileIO::setFileName(const char *fileName) {
{
base->setFileName(fileName); base->setFileName(fileName);
} }
const char *MACFileIO::getFileName() const const char *MACFileIO::getFileName() const { return base->getFileName(); }
{
return base->getFileName();
}
bool MACFileIO::setIV( uint64_t iv ) bool MACFileIO::setIV(uint64_t iv) { return base->setIV(iv); }
{
return base->setIV( iv );
}
inline static off_t roundUpDivide( off_t numerator, int denominator ) inline static off_t roundUpDivide(off_t numerator, int denominator) {
{
// integer arithmetic always rounds down, so we can round up by adding // integer arithmetic always rounds down, so we can round up by adding
// enough so that any value other then a multiple of denominator gets // enough so that any value other then a multiple of denominator gets
// rouned to the next highest value. // rouned to the next highest value.
@ -123,8 +102,7 @@ inline static off_t roundUpDivide( off_t numerator, int denominator )
// ... blockNum = 1 // ... blockNum = 1
// ... partialBlock = 0 // ... partialBlock = 0
// ... adjLoc = 1 * blockSize // ... adjLoc = 1 * blockSize
static off_t locWithHeader( off_t offset, int blockSize, int headerSize ) static off_t locWithHeader(off_t offset, int blockSize, int headerSize) {
{
off_t blockNum = roundUpDivide(offset, blockSize - headerSize); off_t blockNum = roundUpDivide(offset, blockSize - headerSize);
return offset + blockNum * headerSize; return offset + blockNum * headerSize;
} }
@ -134,18 +112,15 @@ static off_t locWithHeader( off_t offset, int blockSize, int headerSize )
// The output value will always be less then the input value, because the // The output value will always be less then the input value, because the
// headers are stored at the beginning of the block, so even the first data is // headers are stored at the beginning of the block, so even the first data is
// offset by the size of the header. // offset by the size of the header.
static off_t locWithoutHeader( off_t offset, int blockSize, int headerSize ) static off_t locWithoutHeader(off_t offset, int blockSize, int headerSize) {
{
off_t blockNum = roundUpDivide(offset, blockSize); off_t blockNum = roundUpDivide(offset, blockSize);
return offset - blockNum * headerSize; return offset - blockNum * headerSize;
} }
int MACFileIO::getAttr( struct stat *stbuf ) const int MACFileIO::getAttr(struct stat *stbuf) const {
{
int res = base->getAttr(stbuf); int res = base->getAttr(stbuf);
if(res == 0 && S_ISREG(stbuf->st_mode)) if (res == 0 && S_ISREG(stbuf->st_mode)) {
{
// have to adjust size field.. // have to adjust size field..
int headerSize = macBytes + randBytes; int headerSize = macBytes + randBytes;
int bs = blockSize() + headerSize; int bs = blockSize() + headerSize;
@ -155,21 +130,18 @@ int MACFileIO::getAttr( struct stat *stbuf ) const
return res; return res;
} }
off_t MACFileIO::getSize() const off_t MACFileIO::getSize() const {
{
// adjust the size to hide the header overhead we tack on.. // adjust the size to hide the header overhead we tack on..
int headerSize = macBytes + randBytes; int headerSize = macBytes + randBytes;
int bs = blockSize() + headerSize; int bs = blockSize() + headerSize;
off_t size = base->getSize(); off_t size = base->getSize();
if(size > 0) if (size > 0) size = locWithoutHeader(size, bs, headerSize);
size = locWithoutHeader( size, bs, headerSize );
return size; return size;
} }
ssize_t MACFileIO::readOneBlock( const IORequest &req ) const ssize_t MACFileIO::readOneBlock(const IORequest &req) const {
{
int headerSize = macBytes + randBytes; int headerSize = macBytes + randBytes;
int bs = blockSize() + headerSize; int bs = blockSize() + headerSize;
@ -186,47 +158,38 @@ ssize_t MACFileIO::readOneBlock( const IORequest &req ) const
// don't store zeros if configured for zero-block pass-through // don't store zeros if configured for zero-block pass-through
bool skipBlock = true; bool skipBlock = true;
if( _allowHoles ) if (_allowHoles) {
{
for (int i = 0; i < readSize; ++i) for (int i = 0; i < readSize; ++i)
if(tmp.data[i] != 0) if (tmp.data[i] != 0) {
{
skipBlock = false; skipBlock = false;
break; break;
} }
} else if (macBytes > 0) } else if (macBytes > 0)
skipBlock = false; skipBlock = false;
if(readSize > headerSize) if (readSize > headerSize) {
{ if (!skipBlock) {
if(!skipBlock)
{
// At this point the data has been decoded. So, compute the MAC of // At this point the data has been decoded. So, compute the MAC of
// the block and check against the checksum stored in the header.. // the block and check against the checksum stored in the header..
uint64_t mac = cipher->MAC_64( tmp.data + macBytes, uint64_t mac =
readSize - macBytes, key ); cipher->MAC_64(tmp.data + macBytes, readSize - macBytes, key);
// Constant time comparision to prevent timing attacks // Constant time comparision to prevent timing attacks
unsigned char fail = 0; unsigned char fail = 0;
for(int i=0; i<macBytes; ++i, mac >>= 8) for (int i = 0; i < macBytes; ++i, mac >>= 8) {
{
int test = mac & 0xff; int test = mac & 0xff;
int stored = tmp.data[i]; int stored = tmp.data[i];
fail |= (test ^ stored); fail |= (test ^ stored);
} }
if( fail > 0 ) if (fail > 0) {
{
// uh oh.. // uh oh..
long blockNum = req.offset / bs; long blockNum = req.offset / bs;
rWarning(_("MAC comparison failure in block %li"), rWarning(_("MAC comparison failure in block %li"), blockNum);
blockNum); if (!warnOnly) {
if( !warnOnly )
{
MemoryPool::release(mb); MemoryPool::release(mb);
throw ERROR( throw ERROR(_("MAC comparison failure, refusing to read"));
_("MAC comparison failure, refusing to read"));
} }
} }
} }
@ -234,11 +197,9 @@ ssize_t MACFileIO::readOneBlock( const IORequest &req ) const
// now copy the data to the output buffer // now copy the data to the output buffer
readSize -= headerSize; readSize -= headerSize;
memcpy(req.data, tmp.data + headerSize, readSize); memcpy(req.data, tmp.data + headerSize, readSize);
} else } else {
{
rDebug("readSize %i at offset %" PRIi64, (int)readSize, req.offset); rDebug("readSize %i at offset %" PRIi64, (int)readSize, req.offset);
if(readSize > 0) if (readSize > 0) readSize = 0;
readSize = 0;
} }
MemoryPool::release(mb); MemoryPool::release(mb);
@ -246,8 +207,7 @@ ssize_t MACFileIO::readOneBlock( const IORequest &req ) const
return readSize; return readSize;
} }
bool MACFileIO::writeOneBlock( const IORequest &req ) bool MACFileIO::writeOneBlock(const IORequest &req) {
{
int headerSize = macBytes + randBytes; int headerSize = macBytes + randBytes;
int bs = blockSize() + headerSize; int bs = blockSize() + headerSize;
@ -262,20 +222,17 @@ bool MACFileIO::writeOneBlock( const IORequest &req )
memset(newReq.data, 0, headerSize); memset(newReq.data, 0, headerSize);
memcpy(newReq.data + headerSize, req.data, req.dataLen); memcpy(newReq.data + headerSize, req.data, req.dataLen);
if(randBytes > 0) if (randBytes > 0) {
{
if (!cipher->randomize(newReq.data + macBytes, randBytes, false)) if (!cipher->randomize(newReq.data + macBytes, randBytes, false))
return false; return false;
} }
if(macBytes > 0) if (macBytes > 0) {
{
// compute the mac (which includes the random data) and fill it in // compute the mac (which includes the random data) and fill it in
uint64_t mac = cipher->MAC_64( newReq.data+macBytes, uint64_t mac =
req.dataLen + randBytes, key ); cipher->MAC_64(newReq.data + macBytes, req.dataLen + randBytes, key);
for(int i=0; i<macBytes; ++i) for (int i = 0; i < macBytes; ++i) {
{
newReq.data[i] = mac & 0xff; newReq.data[i] = mac & 0xff;
mac >>= 8; mac >>= 8;
} }
@ -289,20 +246,15 @@ bool MACFileIO::writeOneBlock( const IORequest &req )
return ok; return ok;
} }
int MACFileIO::truncate( off_t size ) int MACFileIO::truncate(off_t size) {
{
int headerSize = macBytes + randBytes; int headerSize = macBytes + randBytes;
int bs = blockSize() + headerSize; int bs = blockSize() + headerSize;
int res = BlockFileIO::truncateBase(size, 0); int res = BlockFileIO::truncateBase(size, 0);
if(res == 0) if (res == 0) base->truncate(locWithHeader(size, bs, headerSize));
base->truncate( locWithHeader( size, bs, headerSize ) );
return res; return res;
} }
bool MACFileIO::isWritable() const bool MACFileIO::isWritable() const { return base->isWritable(); }
{
return base->isWritable();
}

View File

@ -24,16 +24,14 @@
#include "BlockFileIO.h" #include "BlockFileIO.h"
#include "Cipher.h" #include "Cipher.h"
class MACFileIO : public BlockFileIO class MACFileIO : public BlockFileIO {
{
public: public:
/* /*
If warnOnlyMode is enabled, then a MAC comparison failure will only If warnOnlyMode is enabled, then a MAC comparison failure will only
result in a warning message from encfs -- the garbled data will still result in a warning message from encfs -- the garbled data will still
be made available.. be made available..
*/ */
MACFileIO( const shared_ptr<FileIO> &base, MACFileIO(const shared_ptr<FileIO> &base, const FSConfigPtr &cfg);
const FSConfigPtr &cfg );
MACFileIO(); MACFileIO();
virtual ~MACFileIO(); virtual ~MACFileIO();
@ -64,4 +62,3 @@ private:
}; };
#endif #endif

View File

@ -39,16 +39,13 @@ using namespace rlog;
#include <openssl/buffer.h> #include <openssl/buffer.h>
#define BLOCKDATA(BLOCK) (unsigned char *) BLOCK->data->data #define BLOCKDATA(BLOCK) (unsigned char *) BLOCK->data->data
struct BlockList {
struct BlockList
{
BlockList *next; BlockList *next;
int size; int size;
BUF_MEM *data; BUF_MEM *data;
}; };
static BlockList *allocBlock( int size ) static BlockList *allocBlock(int size) {
{
BlockList *block = new BlockList; BlockList *block = new BlockList;
block->size = size; block->size = size;
block->data = BUF_MEM_new(); block->data = BUF_MEM_new();
@ -58,8 +55,7 @@ static BlockList *allocBlock( int size )
return block; return block;
} }
static void freeBlock( BlockList *el ) static void freeBlock(BlockList *el) {
{
VALGRIND_MAKE_MEM_UNDEFINED(el->data->data, el->data->max); VALGRIND_MAKE_MEM_UNDEFINED(el->data->data, el->data->max);
BUF_MEM_free(el->data); BUF_MEM_free(el->data);
@ -69,24 +65,19 @@ static void freeBlock( BlockList *el )
static pthread_mutex_t gMPoolMutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t gMPoolMutex = PTHREAD_MUTEX_INITIALIZER;
static BlockList *gMemPool = NULL; static BlockList *gMemPool = NULL;
MemBlock MemoryPool::allocate(int size) {
MemBlock MemoryPool::allocate( int size )
{
pthread_mutex_lock(&gMPoolMutex); pthread_mutex_lock(&gMPoolMutex);
BlockList *parent = NULL; BlockList *parent = NULL;
BlockList *block = gMemPool; BlockList *block = gMemPool;
// check if we already have a large enough block available.. // check if we already have a large enough block available..
while(block != NULL && block->size < size) while (block != NULL && block->size < size) {
{
parent = block; parent = block;
block = block->next; block = block->next;
} }
// unlink block from list // unlink block from list
if(block) if (block) {
{
if (!parent) if (!parent)
gMemPool = block->next; gMemPool = block->next;
else else
@ -94,8 +85,7 @@ MemBlock MemoryPool::allocate( int size )
} }
pthread_mutex_unlock(&gMPoolMutex); pthread_mutex_unlock(&gMPoolMutex);
if(!block) if (!block) block = allocBlock(size);
block = allocBlock( size );
block->next = NULL; block->next = NULL;
MemBlock result; MemBlock result;
@ -107,8 +97,7 @@ MemBlock MemoryPool::allocate( int size )
return result; return result;
} }
void MemoryPool::release( const MemBlock &mb ) void MemoryPool::release(const MemBlock &mb) {
{
pthread_mutex_lock(&gMPoolMutex); pthread_mutex_lock(&gMPoolMutex);
BlockList *block = (BlockList *)mb.internalData; BlockList *block = (BlockList *)mb.internalData;
@ -124,8 +113,7 @@ void MemoryPool::release( const MemBlock &mb )
pthread_mutex_unlock(&gMPoolMutex); pthread_mutex_unlock(&gMPoolMutex);
} }
void MemoryPool::destroyAll() void MemoryPool::destroyAll() {
{
pthread_mutex_lock(&gMPoolMutex); pthread_mutex_lock(&gMPoolMutex);
BlockList *block = gMemPool; BlockList *block = gMemPool;
@ -133,13 +121,10 @@ void MemoryPool::destroyAll()
pthread_mutex_unlock(&gMPoolMutex); pthread_mutex_unlock(&gMPoolMutex);
while(block != NULL) while (block != NULL) {
{
BlockList *next = block->next; BlockList *next = block->next;
freeBlock(block); freeBlock(block);
block = next; block = next;
} }
} }

View File

@ -21,9 +21,7 @@
#ifndef _MemoryPool_incl_ #ifndef _MemoryPool_incl_
#define _MemoryPool_incl_ #define _MemoryPool_incl_
struct MemBlock {
struct MemBlock
{
unsigned char *data; unsigned char *data;
void *internalData; void *internalData;
@ -31,10 +29,7 @@ struct MemBlock
MemBlock(); MemBlock();
}; };
inline MemBlock::MemBlock() inline MemBlock::MemBlock() : data(0), internalData(0) {}
: data(0), internalData(0)
{
}
/* /*
Memory Pool for fixed sized objects. Memory Pool for fixed sized objects.
@ -45,12 +40,10 @@ inline MemBlock::MemBlock()
unsigned char *buffer = mb.data; unsigned char *buffer = mb.data;
MemoryPool::release( mb ); MemoryPool::release( mb );
*/ */
namespace MemoryPool namespace MemoryPool {
{
MemBlock allocate(int size); MemBlock allocate(int size);
void release(const MemBlock &el); void release(const MemBlock &el);
void destroyAll(); void destroyAll();
} }
#endif #endif

View File

@ -23,11 +23,9 @@
#include <pthread.h> #include <pthread.h>
namespace rel namespace rel {
{
class Lock class Lock {
{
public: public:
Lock(pthread_mutex_t &mutex); Lock(pthread_mutex_t &mutex);
~Lock(); ~Lock();
@ -43,23 +41,15 @@ namespace rel
pthread_mutex_t *_mutex; pthread_mutex_t *_mutex;
}; };
inline Lock::Lock( pthread_mutex_t &mutex ) inline Lock::Lock(pthread_mutex_t &mutex) : _mutex(&mutex) {
: _mutex( &mutex )
{
pthread_mutex_lock(_mutex); pthread_mutex_lock(_mutex);
} }
inline Lock::~Lock( ) inline Lock::~Lock() {
{ if (_mutex) pthread_mutex_unlock(_mutex);
if(_mutex)
pthread_mutex_unlock( _mutex );
} }
inline void Lock::leave() inline void Lock::leave() { _mutex = 0; }
{
_mutex = 0;
}
} }
#endif #endif

View File

@ -39,20 +39,15 @@ using namespace rel;
using namespace rlog; using namespace rlog;
#define REF_MODULE(TYPE) \ #define REF_MODULE(TYPE) \
if(!TYPE::Enabled() ) \ if (!TYPE::Enabled()) cerr << "referenceModule: should never happen\n";
cerr << "referenceModule: should never happen\n";
static static void AddSymbolReferences() {
void AddSymbolReferences()
{
REF_MODULE(BlockNameIO) REF_MODULE(BlockNameIO)
REF_MODULE(StreamNameIO) REF_MODULE(StreamNameIO)
REF_MODULE(NullNameIO) REF_MODULE(NullNameIO)
} }
struct NameIOAlg {
struct NameIOAlg
{
bool hidden; bool hidden;
NameIO::Constructor constructor; NameIO::Constructor constructor;
string description; string description;
@ -62,21 +57,15 @@ struct NameIOAlg
typedef multimap<string, NameIOAlg> NameIOMap_t; typedef multimap<string, NameIOAlg> NameIOMap_t;
static NameIOMap_t *gNameIOMap = 0; static NameIOMap_t *gNameIOMap = 0;
list<NameIO::Algorithm> NameIO::GetAlgorithmList(bool includeHidden) {
list< NameIO::Algorithm >
NameIO::GetAlgorithmList( bool includeHidden )
{
AddSymbolReferences(); AddSymbolReferences();
list<Algorithm> result; list<Algorithm> result;
if(gNameIOMap) if (gNameIOMap) {
{
NameIOMap_t::const_iterator it; NameIOMap_t::const_iterator it;
NameIOMap_t::const_iterator end = gNameIOMap->end(); NameIOMap_t::const_iterator end = gNameIOMap->end();
for(it = gNameIOMap->begin(); it != end; ++it) for (it = gNameIOMap->begin(); it != end; ++it) {
{ if (includeHidden || !it->second.hidden) {
if(includeHidden || !it->second.hidden)
{
Algorithm tmp; Algorithm tmp;
tmp.name = it->first; tmp.name = it->first;
tmp.description = it->second.description; tmp.description = it->second.description;
@ -92,10 +81,8 @@ NameIO::GetAlgorithmList( bool includeHidden )
bool NameIO::Register(const char *name, const char *description, bool NameIO::Register(const char *name, const char *description,
const Interface &iface, Constructor constructor, const Interface &iface, Constructor constructor,
bool hidden ) bool hidden) {
{ if (!gNameIOMap) gNameIOMap = new NameIOMap_t;
if( !gNameIOMap )
gNameIOMap = new NameIOMap_t;
NameIOAlg alg; NameIOAlg alg;
alg.hidden = hidden; alg.hidden = hidden;
@ -108,14 +95,12 @@ bool NameIO::Register( const char *name, const char *description,
} }
shared_ptr<NameIO> NameIO::New(const string &name, shared_ptr<NameIO> NameIO::New(const string &name,
const shared_ptr<Cipher> &cipher, const CipherKey &key) const shared_ptr<Cipher> &cipher,
{ const CipherKey &key) {
shared_ptr<NameIO> result; shared_ptr<NameIO> result;
if(gNameIOMap) if (gNameIOMap) {
{
NameIOMap_t::const_iterator it = gNameIOMap->find(name); NameIOMap_t::const_iterator it = gNameIOMap->find(name);
if(it != gNameIOMap->end()) if (it != gNameIOMap->end()) {
{
Constructor fn = it->second.constructor; Constructor fn = it->second.constructor;
result = (*fn)(it->second.iface, cipher, key); result = (*fn)(it->second.iface, cipher, key);
} }
@ -124,17 +109,14 @@ shared_ptr<NameIO> NameIO::New( const string &name,
} }
shared_ptr<NameIO> NameIO::New(const Interface &iface, shared_ptr<NameIO> NameIO::New(const Interface &iface,
const shared_ptr<Cipher> &cipher, const CipherKey &key ) const shared_ptr<Cipher> &cipher,
{ const CipherKey &key) {
shared_ptr<NameIO> result; shared_ptr<NameIO> result;
if(gNameIOMap) if (gNameIOMap) {
{
NameIOMap_t::const_iterator it; NameIOMap_t::const_iterator it;
NameIOMap_t::const_iterator end = gNameIOMap->end(); NameIOMap_t::const_iterator end = gNameIOMap->end();
for(it = gNameIOMap->begin(); it != end; ++it) for (it = gNameIOMap->begin(); it != end; ++it) {
{ if (it->second.iface.implements(iface)) {
if( it->second.iface.implements( iface ))
{
Constructor fn = it->second.constructor; Constructor fn = it->second.constructor;
result = (*fn)(iface, cipher, key); result = (*fn)(iface, cipher, key);
break; break;
@ -144,61 +126,37 @@ shared_ptr<NameIO> NameIO::New( const Interface &iface,
return result; return result;
} }
NameIO::NameIO() : chainedNameIV(false), reverseEncryption(false) {}
NameIO::~NameIO() {}
NameIO::NameIO() void NameIO::setChainedNameIV(bool enable) { chainedNameIV = enable; }
: chainedNameIV( false ), reverseEncryption( false )
{
}
NameIO::~NameIO() bool NameIO::getChainedNameIV() const { return chainedNameIV; }
{
}
void NameIO::setChainedNameIV( bool enable ) void NameIO::setReverseEncryption(bool enable) { reverseEncryption = enable; }
{
chainedNameIV = enable;
}
bool NameIO::getChainedNameIV() const
{
return chainedNameIV;
}
void NameIO::setReverseEncryption( bool enable )
{
reverseEncryption = enable;
}
bool NameIO::getReverseEncryption() const
{
return reverseEncryption;
}
bool NameIO::getReverseEncryption() const { return reverseEncryption; }
std::string NameIO::recodePath(const char *path, std::string NameIO::recodePath(const char *path,
int (NameIO::*_length)(int) const, int (NameIO::*_length)(int) const,
int (NameIO::*_code)(const char*, int, uint64_t *, char*) const, int (NameIO::*_code)(const char *, int,
uint64_t *iv ) const uint64_t *, char *) const,
{ uint64_t *iv) const {
string output; string output;
while( *path ) while (*path) {
{ if (*path == '/') {
if( *path == '/' )
{
if (!output.empty()) // don't start the string with '/' if (!output.empty()) // don't start the string with '/'
output += '/'; output += '/';
++path; ++path;
} else } else {
{
bool isDotFile = (*path == '.'); bool isDotFile = (*path == '.');
const char *next = strchr(path, '/'); const char *next = strchr(path, '/');
int len = next ? next - path : strlen(path); int len = next ? next - path : strlen(path);
// at this point we know that len > 0 // at this point we know that len > 0
if( isDotFile && (path[len-1] == '.') && (len <= 2) ) if (isDotFile && (path[len - 1] == '.') && (len <= 2)) {
{
output.append(len, '.'); // append [len] copies of '.' output.append(len, '.'); // append [len] copies of '.'
path += len; path += len;
continue; continue;
@ -206,8 +164,7 @@ std::string NameIO::recodePath( const char *path,
// figure out buffer sizes // figure out buffer sizes
int approxLen = (this->*_length)(len); int approxLen = (this->*_length)(len);
if(approxLen <= 0) if (approxLen <= 0) throw ERROR("Filename too small to decode");
throw ERROR("Filename too small to decode");
BUFFER_INIT(codeBuf, 32, (unsigned int)approxLen + 1) BUFFER_INIT(codeBuf, 32, (unsigned int)approxLen + 1)
@ -227,63 +184,47 @@ std::string NameIO::recodePath( const char *path,
return output; return output;
} }
std::string NameIO::encodePath( const char *plaintextPath ) const std::string NameIO::encodePath(const char *plaintextPath) const {
{
uint64_t iv = 0; uint64_t iv = 0;
return encodePath(plaintextPath, &iv); return encodePath(plaintextPath, &iv);
} }
std::string NameIO::decodePath( const char *cipherPath ) const std::string NameIO::decodePath(const char *cipherPath) const {
{
uint64_t iv = 0; uint64_t iv = 0;
return decodePath(cipherPath, &iv); return decodePath(cipherPath, &iv);
} }
std::string NameIO::_encodePath( const char *plaintextPath, uint64_t *iv ) const std::string NameIO::_encodePath(const char *plaintextPath, uint64_t *iv) const {
{
// if chaining is not enabled, then the iv pointer is not used.. // if chaining is not enabled, then the iv pointer is not used..
if(!chainedNameIV) if (!chainedNameIV) iv = 0;
iv = 0; return recodePath(plaintextPath, &NameIO::maxEncodedNameLen,
return recodePath( plaintextPath, &NameIO::encodeName, iv);
&NameIO::maxEncodedNameLen, &NameIO::encodeName, iv);
} }
std::string NameIO::_decodePath( const char *cipherPath, uint64_t *iv ) const std::string NameIO::_decodePath(const char *cipherPath, uint64_t *iv) const {
{
// if chaining is not enabled, then the iv pointer is not used.. // if chaining is not enabled, then the iv pointer is not used..
if(!chainedNameIV) if (!chainedNameIV) iv = 0;
iv = 0; return recodePath(cipherPath, &NameIO::maxDecodedNameLen, &NameIO::decodeName,
return recodePath( cipherPath, iv);
&NameIO::maxDecodedNameLen, &NameIO::decodeName, iv);
} }
std::string NameIO::encodePath( const char *path, uint64_t *iv ) const std::string NameIO::encodePath(const char *path, uint64_t *iv) const {
{ return getReverseEncryption() ? _decodePath(path, iv) : _encodePath(path, iv);
return getReverseEncryption() ?
_decodePath( path, iv ) :
_encodePath( path, iv );
} }
std::string NameIO::decodePath( const char *path, uint64_t *iv ) const std::string NameIO::decodePath(const char *path, uint64_t *iv) const {
{ return getReverseEncryption() ? _encodePath(path, iv) : _decodePath(path, iv);
return getReverseEncryption() ?
_encodePath( path, iv ) :
_decodePath( path, iv );
} }
int NameIO::encodeName(const char *input, int length, char *output) const {
int NameIO::encodeName( const char *input, int length, char *output ) const
{
return encodeName(input, length, (uint64_t *)0, output); return encodeName(input, length, (uint64_t *)0, output);
} }
int NameIO::decodeName( const char *input, int length, char *output ) const int NameIO::decodeName(const char *input, int length, char *output) const {
{
return decodeName(input, length, (uint64_t *)0, output); return decodeName(input, length, (uint64_t *)0, output);
} }
std::string NameIO::_encodeName( const char *plaintextName, int length ) const std::string NameIO::_encodeName(const char *plaintextName, int length) const {
{
int approxLen = maxEncodedNameLen(length); int approxLen = maxEncodedNameLen(length);
BUFFER_INIT(codeBuf, 32, (unsigned int)approxLen + 1) BUFFER_INIT(codeBuf, 32, (unsigned int)approxLen + 1)
@ -301,8 +242,7 @@ std::string NameIO::_encodeName( const char *plaintextName, int length ) const
return result; return result;
} }
std::string NameIO::_decodeName( const char *encodedName, int length ) const std::string NameIO::_decodeName(const char *encodedName, int length) const {
{
int approxLen = maxDecodedNameLen(length); int approxLen = maxDecodedNameLen(length);
BUFFER_INIT(codeBuf, 32, (unsigned int)approxLen + 1) BUFFER_INIT(codeBuf, 32, (unsigned int)approxLen + 1)
@ -320,18 +260,14 @@ std::string NameIO::_decodeName( const char *encodedName, int length ) const
return result; return result;
} }
std::string NameIO::encodeName( const char *path, int length ) const std::string NameIO::encodeName(const char *path, int length) const {
{ return getReverseEncryption() ? _decodeName(path, length)
return getReverseEncryption() ? : _encodeName(path, length);
_decodeName( path, length ) :
_encodeName( path, length );
} }
std::string NameIO::decodeName( const char *path, int length ) const std::string NameIO::decodeName(const char *path, int length) const {
{ return getReverseEncryption() ? _encodeName(path, length)
return getReverseEncryption() ? : _decodeName(path, length);
_encodeName( path, length ) :
_decodeName( path, length );
} }
/* /*
int NameIO::encodeName( const char *path, int length, int NameIO::encodeName( const char *path, int length,

View File

@ -31,14 +31,13 @@
class Cipher; class Cipher;
class NameIO class NameIO {
{
public: public:
typedef shared_ptr<NameIO>(*Constructor)(const rel::Interface &iface, typedef shared_ptr<NameIO>(*Constructor)(const rel::Interface &iface,
const shared_ptr<Cipher> &cipher, const CipherKey &key); const shared_ptr<Cipher> &cipher,
const CipherKey &key);
struct Algorithm struct Algorithm {
{
std::string name; std::string name;
std::string description; std::string description;
rel::Interface iface; rel::Interface iface;
@ -48,15 +47,16 @@ public:
static AlgorithmList GetAlgorithmList(bool includeHidden = false); static AlgorithmList GetAlgorithmList(bool includeHidden = false);
static shared_ptr<NameIO> New(const rel::Interface &iface, static shared_ptr<NameIO> New(const rel::Interface &iface,
const shared_ptr<Cipher> &cipher, const CipherKey &key); const shared_ptr<Cipher> &cipher,
const CipherKey &key);
static shared_ptr<NameIO> New(const std::string &name, static shared_ptr<NameIO> New(const std::string &name,
const shared_ptr<Cipher> &cipher, const CipherKey &key); const shared_ptr<Cipher> &cipher,
const CipherKey &key);
static bool Register(const char *name, const char *description, static bool Register(const char *name, const char *description,
const rel::Interface &iface, Constructor constructor, const rel::Interface &iface, Constructor constructor,
bool hidden = false); bool hidden = false);
NameIO(); NameIO();
virtual ~NameIO(); virtual ~NameIO();
@ -85,16 +85,13 @@ protected:
virtual int decodeName(const char *encodedName, int length, virtual int decodeName(const char *encodedName, int length,
char *plaintextName) const; char *plaintextName) const;
virtual int encodeName( const char *plaintextName, int length, virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
uint64_t *iv, char *encodedName ) const =0; char *encodedName) const = 0;
virtual int decodeName( const char *encodedName, int length, virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
uint64_t *iv, char *plaintextName ) const =0; char *plaintextName) const = 0;
private: private:
std::string recodePath(const char *path, int (NameIO::*codingLen)(int) const,
std::string recodePath( const char *path,
int (NameIO::*codingLen)(int) const,
int (NameIO::*codingFunc)(const char *, int, int (NameIO::*codingFunc)(const char *, int,
uint64_t *, char *) const, uint64_t *, char *) const,
uint64_t *iv) const; uint64_t *iv) const;
@ -108,8 +105,6 @@ private:
bool reverseEncryption; bool reverseEncryption;
}; };
/* /*
Helper macros for creating temporary buffers with an optimization that Helper macros for creating temporary buffers with an optimization that
below a given size (OptimizedSize) is allocated on the stack, and when a below a given size (OptimizedSize) is allocated on the stack, and when a
@ -120,19 +115,15 @@ private:
#define BUFFER_INIT(Name, OptimizedSize, Size) \ #define BUFFER_INIT(Name, OptimizedSize, Size) \
char Name##_Raw[OptimizedSize]; \ char Name##_Raw[OptimizedSize]; \
char *Name = Name##_Raw; \ char *Name = Name##_Raw; \
if( sizeof(Name ## _Raw) < Size ) \ if (sizeof(Name##_Raw) < Size) Name = new char[Size]; \
Name = new char[ Size ];\
memset(Name, 0, Size); memset(Name, 0, Size);
#define BUFFER_RESET(Name) \ #define BUFFER_RESET(Name) \
do { \ do { \
if( Name != Name ## _Raw ) \ if (Name != Name##_Raw) { \
{ \
delete[] Name; \ delete[] Name; \
Name = Name##_Raw; \ Name = Name##_Raw; \
} \ } \
} while (0); } while (0);
#endif #endif

View File

@ -18,7 +18,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "NullCipher.h" #include "NullCipher.h"
#include <cstring> #include <cstring>
@ -36,28 +35,24 @@ static Interface NullInterface( "nullCipher", 1, 0, 0 );
static Range NullKeyRange(0); static Range NullKeyRange(0);
static Range NullBlockRange(1, 4096, 1); static Range NullBlockRange(1, 4096, 1);
static shared_ptr<Cipher> NewNullCipher(const Interface &iface, int keyLen) static shared_ptr<Cipher> NewNullCipher(const Interface &iface, int keyLen) {
{
(void)keyLen; (void)keyLen;
return shared_ptr<Cipher>(new NullCipher(iface)); return shared_ptr<Cipher>(new NullCipher(iface));
} }
const bool HiddenCipher = true; const bool HiddenCipher = true;
static bool NullCipher_registered = Cipher::Register("Null", static bool NullCipher_registered = Cipher::Register(
"Non encrypting cipher. For testing only!", "Null", "Non encrypting cipher. For testing only!", NullInterface,
NullInterface, NullKeyRange, NullBlockRange, NewNullCipher, NullKeyRange, NullBlockRange, NewNullCipher, HiddenCipher);
HiddenCipher);
class NullKey : public AbstractCipherKey class NullKey : public AbstractCipherKey {
{
public: public:
NullKey() {} NullKey() {}
virtual ~NullKey() {} virtual ~NullKey() {}
}; };
class NullDestructor class NullDestructor {
{
public: public:
NullDestructor() {} NullDestructor() {}
NullDestructor(const NullDestructor &) {} NullDestructor(const NullDestructor &) {}
@ -69,85 +64,52 @@ public:
shared_ptr<AbstractCipherKey> gNullKey(new NullKey(), NullDestructor()); shared_ptr<AbstractCipherKey> gNullKey(new NullKey(), NullDestructor());
NullCipher::NullCipher(const Interface &iface_) NullCipher::NullCipher(const Interface &iface_) { this->iface = iface_; }
{
this->iface = iface_;
}
NullCipher::~NullCipher() NullCipher::~NullCipher() {}
{
}
Interface NullCipher::interface() const Interface NullCipher::interface() const { return iface; }
{
return iface;
}
CipherKey NullCipher::newKey(const char *, int, CipherKey NullCipher::newKey(const char *, int, int &, long,
int &, long, const unsigned char *, int ) const unsigned char *, int) {
{
return gNullKey; return gNullKey;
} }
CipherKey NullCipher::newKey(const char *, int) CipherKey NullCipher::newKey(const char *, int) { return gNullKey; }
{
return gNullKey;
}
CipherKey NullCipher::newRandomKey() CipherKey NullCipher::newRandomKey() { return gNullKey; }
{
return gNullKey;
}
bool NullCipher::randomize( unsigned char *buf, int len, bool ) const bool NullCipher::randomize(unsigned char *buf, int len, bool) const {
{
memset(buf, 0, len); memset(buf, 0, len);
return true; return true;
} }
uint64_t NullCipher::MAC_64(const unsigned char *, int , uint64_t NullCipher::MAC_64(const unsigned char *, int, const CipherKey &,
const CipherKey &, uint64_t *) const uint64_t *) const {
{
return 0; return 0;
} }
CipherKey NullCipher::readKey( const unsigned char *, CipherKey NullCipher::readKey(const unsigned char *, const CipherKey &, bool) {
const CipherKey &, bool)
{
return gNullKey; return gNullKey;
} }
void NullCipher::writeKey(const CipherKey &, unsigned char *, void NullCipher::writeKey(const CipherKey &, unsigned char *,
const CipherKey &) const CipherKey &) {}
{
}
bool NullCipher::compareKey(const CipherKey &A_, bool NullCipher::compareKey(const CipherKey &A_, const CipherKey &B_) const {
const CipherKey &B_) const
{
shared_ptr<NullKey> A = dynamic_pointer_cast<NullKey>(A_); shared_ptr<NullKey> A = dynamic_pointer_cast<NullKey>(A_);
shared_ptr<NullKey> B = dynamic_pointer_cast<NullKey>(B_); shared_ptr<NullKey> B = dynamic_pointer_cast<NullKey>(B_);
return A.get() == B.get(); return A.get() == B.get();
} }
int NullCipher::encodedKeySize() const int NullCipher::encodedKeySize() const { return 0; }
{
return 0;
}
int NullCipher::keySize() const int NullCipher::keySize() const { return 0; }
{
return 0;
}
int NullCipher::cipherBlockSize() const int NullCipher::cipherBlockSize() const { return 1; }
{
return 1;
}
bool NullCipher::streamEncode( unsigned char *src, int len, bool NullCipher::streamEncode(unsigned char *src, int len, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const const CipherKey &key) const {
{
(void)src; (void)src;
(void)len; (void)len;
(void)iv64; (void)iv64;
@ -155,9 +117,8 @@ bool NullCipher::streamEncode( unsigned char *src, int len,
return true; return true;
} }
bool NullCipher::streamDecode( unsigned char *src, int len, bool NullCipher::streamDecode(unsigned char *src, int len, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const const CipherKey &key) const {
{
(void)src; (void)src;
(void)len; (void)len;
(void)iv64; (void)iv64;
@ -166,19 +127,13 @@ bool NullCipher::streamDecode( unsigned char *src, int len,
} }
bool NullCipher::blockEncode(unsigned char *, int, uint64_t, bool NullCipher::blockEncode(unsigned char *, int, uint64_t,
const CipherKey & ) const const CipherKey &) const {
{
return true; return true;
} }
bool NullCipher::blockDecode(unsigned char *, int, uint64_t, bool NullCipher::blockDecode(unsigned char *, int, uint64_t,
const CipherKey & ) const const CipherKey &) const {
{
return true;
}
bool NullCipher::Enabled()
{
return true; return true;
} }
bool NullCipher::Enabled() { return true; }

View File

@ -28,8 +28,7 @@
Implements Cipher interface for a pass-through mode. May be useful for Implements Cipher interface for a pass-through mode. May be useful for
testing, but that's it. testing, but that's it.
*/ */
class NullCipher : public Cipher class NullCipher : public Cipher {
{
rel::Interface iface; rel::Interface iface;
public: public:
@ -48,39 +47,34 @@ public:
// data must be len keySize() // data must be len keySize()
virtual CipherKey readKey(const unsigned char *data, virtual CipherKey readKey(const unsigned char *data,
const CipherKey &encodingKey, const CipherKey &encodingKey, bool checkKey);
bool checkKey);
virtual void writeKey(const CipherKey &key, unsigned char *data, virtual void writeKey(const CipherKey &key, unsigned char *data,
const CipherKey &encodingKey); const CipherKey &encodingKey);
virtual bool compareKey( const CipherKey &A, virtual bool compareKey(const CipherKey &A, const CipherKey &B) const;
const CipherKey &B ) const;
// meta-data about the cypher // meta-data about the cypher
virtual int keySize() const; virtual int keySize() const;
virtual int encodedKeySize() const; virtual int encodedKeySize() const;
virtual int cipherBlockSize() const; virtual int cipherBlockSize() const;
virtual bool randomize( unsigned char *buf, int len, virtual bool randomize(unsigned char *buf, int len, bool strongRandom) const;
bool strongRandom ) const;
virtual uint64_t MAC_64(const unsigned char *data, int len, virtual uint64_t MAC_64(const unsigned char *data, int len,
const CipherKey &key, uint64_t *chainedIV) const; const CipherKey &key, uint64_t *chainedIV) const;
// functional interfaces // functional interfaces
virtual bool streamEncode(unsigned char *in, int len, virtual bool streamEncode(unsigned char *in, int len, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const; const CipherKey &key) const;
virtual bool streamDecode(unsigned char *in, int len, virtual bool streamDecode(unsigned char *in, int len, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const; const CipherKey &key) const;
virtual bool blockEncode(unsigned char *buf, int size, virtual bool blockEncode(unsigned char *buf, int size, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const; const CipherKey &key) const;
virtual bool blockDecode(unsigned char *buf, int size, virtual bool blockDecode(unsigned char *buf, int size, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const; const CipherKey &key) const;
// hack to help with static builds // hack to help with static builds
static bool Enabled(); static bool Enabled();
}; };
#endif #endif

View File

@ -27,66 +27,45 @@
using namespace rel; using namespace rel;
static shared_ptr<NameIO> NewNNIO( const Interface &, static shared_ptr<NameIO> NewNNIO(const Interface &, const shared_ptr<Cipher> &,
const shared_ptr<Cipher> &, const CipherKey & ) const CipherKey &) {
{
return shared_ptr<NameIO>(new NullNameIO()); return shared_ptr<NameIO>(new NullNameIO());
} }
static Interface NNIOIface("nameio/null", 1, 0, 0); static Interface NNIOIface("nameio/null", 1, 0, 0);
static bool NullNameIO_registered = NameIO::Register("Null", static bool NullNameIO_registered =
"No encryption of filenames", NNIOIface, NewNNIO); NameIO::Register("Null", "No encryption of filenames", NNIOIface, NewNNIO);
NullNameIO::NullNameIO( ) NullNameIO::NullNameIO() {}
{
} NullNameIO::~NullNameIO() {}
NullNameIO::~NullNameIO() Interface NullNameIO::interface() const { return NNIOIface; }
{
}
Interface NullNameIO::interface() const Interface NullNameIO::CurrentInterface() { return NNIOIface; }
{
return NNIOIface;
}
Interface NullNameIO::CurrentInterface() int NullNameIO::maxEncodedNameLen(int plaintextNameLen) const {
{
return NNIOIface;
}
int NullNameIO::maxEncodedNameLen( int plaintextNameLen ) const
{
return plaintextNameLen; return plaintextNameLen;
} }
int NullNameIO::maxDecodedNameLen( int encodedNameLen ) const int NullNameIO::maxDecodedNameLen(int encodedNameLen) const {
{
return encodedNameLen; return encodedNameLen;
} }
int NullNameIO::encodeName( const char *plaintextName, int length, int NullNameIO::encodeName(const char *plaintextName, int length, uint64_t *iv,
uint64_t *iv, char *encodedName ) const char *encodedName) const {
{
(void)iv; (void)iv;
memcpy(encodedName, plaintextName, length); memcpy(encodedName, plaintextName, length);
return length; return length;
} }
int NullNameIO::decodeName( const char *encodedName, int length, int NullNameIO::decodeName(const char *encodedName, int length, uint64_t *iv,
uint64_t *iv, char *plaintextName ) const char *plaintextName) const {
{
(void)iv; (void)iv;
memcpy(plaintextName, encodedName, length); memcpy(plaintextName, encodedName, length);
return length; return length;
} }
bool NullNameIO::Enabled() bool NullNameIO::Enabled() { return true; }
{
return true;
}

View File

@ -23,8 +23,7 @@
#include "NameIO.h" #include "NameIO.h"
class NullNameIO : public NameIO class NullNameIO : public NameIO {
{
public: public:
static rel::Interface CurrentInterface(); static rel::Interface CurrentInterface();
@ -39,14 +38,14 @@ public:
// hack to help with static builds // hack to help with static builds
static bool Enabled(); static bool Enabled();
protected: protected:
virtual int encodeName( const char *plaintextName, int length, virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
uint64_t *iv, char *encodedName ) const; char *encodedName) const;
virtual int decodeName( const char *encodedName, int length, virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
uint64_t *iv, char *plaintextName ) const; char *plaintextName) const;
private: private:
}; };
#endif #endif

View File

@ -21,12 +21,11 @@
#ifndef _Range_incl_ #ifndef _Range_incl_
#define _Range_incl_ #define _Range_incl_
class Range {
class Range
{
int minVal; int minVal;
int maxVal; int maxVal;
int increment; int increment;
public: public:
Range(); Range();
Range(int minMax); Range(int minMax);
@ -41,49 +40,35 @@ public:
int inc() const; int inc() const;
}; };
inline Range::Range(int minMax) inline Range::Range(int minMax) {
{
this->minVal = minMax; this->minVal = minMax;
this->maxVal = minMax; this->maxVal = minMax;
this->increment = 1; this->increment = 1;
} }
inline Range::Range(int min_, int max_, int increment_) inline Range::Range(int min_, int max_, int increment_) {
{
this->minVal = min_; this->minVal = min_;
this->maxVal = max_; this->maxVal = max_;
this->increment = increment_; this->increment = increment_;
if(increment == 0) if (increment == 0) this->increment = 1;
this->increment = 1;
} }
inline Range::Range() inline Range::Range() : minVal(-1), maxVal(-1), increment(1) {}
: minVal(-1)
, maxVal(-1)
, increment(1)
{
}
inline bool Range::allowed(int value) const inline bool Range::allowed(int value) const {
{ if (value >= minVal && value <= maxVal) {
if(value >= minVal && value <= maxVal)
{
int tmp = value - minVal; int tmp = value - minVal;
if((tmp % increment) == 0) if ((tmp % increment) == 0) return true;
return true;
} }
return false; return false;
} }
inline int Range::closest(int value) const inline int Range::closest(int value) const {
{
if (allowed(value)) if (allowed(value))
return value; return value;
else else if (value < minVal)
if(value < minVal)
return minVal; return minVal;
else else if (value > maxVal)
if(value > maxVal)
return maxVal; return maxVal;
// must be inbetween but not matched with increment // must be inbetween but not matched with increment
@ -95,19 +80,10 @@ inline int Range::closest(int value) const
return closest(value + tmp); return closest(value + tmp);
} }
inline int Range::min() const inline int Range::min() const { return minVal; }
{
return minVal;
}
inline int Range::max() const inline int Range::max() const { return maxVal; }
{
return maxVal;
}
inline int Range::inc() const inline int Range::inc() const { return increment; }
{
return increment;
}
#endif #endif

View File

@ -38,57 +38,41 @@ using namespace std;
static rel::Interface RawFileIO_iface("FileIO/Raw", 1, 0, 0); static rel::Interface RawFileIO_iface("FileIO/Raw", 1, 0, 0);
FileIO *NewRawFileIO( const rel::Interface &iface ) FileIO *NewRawFileIO(const rel::Interface &iface) {
{
(void)iface; (void)iface;
return new RawFileIO(); return new RawFileIO();
} }
inline void swap( int &x, int &y ) inline void swap(int &x, int &y) {
{
int tmp = x; int tmp = x;
x = y; x = y;
y = tmp; y = tmp;
} }
RawFileIO::RawFileIO() RawFileIO::RawFileIO()
: knownSize( false ) : knownSize(false), fileSize(0), fd(-1), oldfd(-1), canWrite(false) {}
, fileSize(0)
, fd( -1 )
, oldfd( -1 )
, canWrite( false )
{
}
RawFileIO::RawFileIO(const std::string &fileName) RawFileIO::RawFileIO(const std::string &fileName)
: name( fileName ) : name(fileName),
, knownSize( false ) knownSize(false),
, fileSize( 0 ) fileSize(0),
, fd( -1 ) fd(-1),
, oldfd( -1 ) oldfd(-1),
, canWrite( false ) canWrite(false) {}
{
}
RawFileIO::~RawFileIO() RawFileIO::~RawFileIO() {
{
int _fd = -1; int _fd = -1;
int _oldfd = -1; int _oldfd = -1;
swap(_fd, fd); swap(_fd, fd);
swap(_oldfd, oldfd); swap(_oldfd, oldfd);
if( _oldfd != -1 ) if (_oldfd != -1) close(_oldfd);
close( _oldfd );
if( _fd != -1 ) if (_fd != -1) close(_fd);
close( _fd );
} }
rel::Interface RawFileIO::interface() const rel::Interface RawFileIO::interface() const { return RawFileIO_iface; }
{
return RawFileIO_iface;
}
/* /*
Workaround for opening a file for write when permissions don't allow. Workaround for opening a file for write when permissions don't allow.
@ -97,19 +81,16 @@ rel::Interface RawFileIO::interface() const
be called with a lock around it so that there won't be a race condition be called with a lock around it so that there won't be a race condition
with calls to lstat picking up the wrong permissions. with calls to lstat picking up the wrong permissions.
*/ */
static int open_readonly_workaround(const char *path, int flags) static int open_readonly_workaround(const char *path, int flags) {
{
int fd = -1; int fd = -1;
struct stat stbuf; struct stat stbuf;
memset(&stbuf, 0, sizeof(struct stat)); memset(&stbuf, 0, sizeof(struct stat));
if(lstat( path, &stbuf ) != -1) if (lstat(path, &stbuf) != -1) {
{
// make sure user has read/write permission.. // make sure user has read/write permission..
chmod(path, stbuf.st_mode | 0600); chmod(path, stbuf.st_mode | 0600);
fd = ::open(path, flags); fd = ::open(path, flags);
chmod(path, stbuf.st_mode); chmod(path, stbuf.st_mode);
} else } else {
{
rInfo("can't stat file %s", path); rInfo("can't stat file %s", path);
} }
@ -125,8 +106,7 @@ static int open_readonly_workaround(const char *path, int flags)
- Also keep the O_LARGEFILE flag, in case the underlying filesystem needs - Also keep the O_LARGEFILE flag, in case the underlying filesystem needs
it.. it..
*/ */
int RawFileIO::open(int flags) int RawFileIO::open(int flags) {
{
bool requestWrite = ((flags & O_RDWR) || (flags & O_WRONLY)); bool requestWrite = ((flags & O_RDWR) || (flags & O_WRONLY));
rDebug("open call for %s file", requestWrite ? "writable" : "read only"); rDebug("open call for %s file", requestWrite ? "writable" : "read only");
@ -134,17 +114,14 @@ int RawFileIO::open(int flags)
int result = 0; int result = 0;
// if we have a descriptor and it is writable, or we don't need writable.. // if we have a descriptor and it is writable, or we don't need writable..
if((fd >= 0) && (canWrite || !requestWrite)) if ((fd >= 0) && (canWrite || !requestWrite)) {
{
rDebug("using existing file descriptor"); rDebug("using existing file descriptor");
result = fd; // success result = fd; // success
} else } else {
{
int finalFlags = requestWrite ? O_RDWR : O_RDONLY; int finalFlags = requestWrite ? O_RDWR : O_RDONLY;
#if defined(O_LARGEFILE) #if defined(O_LARGEFILE)
if( flags & O_LARGEFILE ) if (flags & O_LARGEFILE) finalFlags |= O_LARGEFILE;
finalFlags |= O_LARGEFILE;
#else #else
#warning O_LARGEFILE not supported #warning O_LARGEFILE not supported
#endif #endif
@ -153,18 +130,15 @@ int RawFileIO::open(int flags)
rDebug("open file with flags %i, result = %i", finalFlags, newFd); rDebug("open file with flags %i, result = %i", finalFlags, newFd);
if((newFd == -1) && (errno == EACCES)) if ((newFd == -1) && (errno == EACCES)) {
{
rDebug("using readonly workaround for open"); rDebug("using readonly workaround for open");
newFd = open_readonly_workaround(name.c_str(), finalFlags); newFd = open_readonly_workaround(name.c_str(), finalFlags);
} }
if(newFd >= 0) if (newFd >= 0) {
{ if (oldfd >= 0) {
if(oldfd >= 0) rError("leaking FD?: oldfd = %i, fd = %i, newfd = %i", oldfd, fd,
{ newFd);
rError("leaking FD?: oldfd = %i, fd = %i, newfd = %i",
oldfd, fd, newFd);
} }
// the old fd might still be in use, so just keep it around for // the old fd might still be in use, so just keep it around for
@ -172,78 +146,61 @@ int RawFileIO::open(int flags)
canWrite = requestWrite; canWrite = requestWrite;
oldfd = fd; oldfd = fd;
result = fd = newFd; result = fd = newFd;
} else } else {
{
result = -errno; result = -errno;
rInfo("::open error: %s", strerror(errno)); rInfo("::open error: %s", strerror(errno));
} }
} }
if(result < 0) if (result < 0) rInfo("file %s open failure: %i", name.c_str(), -result);
rInfo("file %s open failure: %i", name.c_str(), -result);
return result; return result;
} }
int RawFileIO::getAttr( struct stat *stbuf ) const int RawFileIO::getAttr(struct stat *stbuf) const {
{
int res = lstat(name.c_str(), stbuf); int res = lstat(name.c_str(), stbuf);
int eno = errno; int eno = errno;
if(res < 0) if (res < 0) rInfo("getAttr error on %s: %s", name.c_str(), strerror(eno));
rInfo("getAttr error on %s: %s", name.c_str(), strerror( eno ));
return (res < 0) ? -eno : 0; return (res < 0) ? -eno : 0;
} }
void RawFileIO::setFileName( const char *fileName ) void RawFileIO::setFileName(const char *fileName) { name = fileName; }
{
name = fileName;
}
const char *RawFileIO::getFileName() const const char *RawFileIO::getFileName() const { return name.c_str(); }
{
return name.c_str();
}
off_t RawFileIO::getSize() const off_t RawFileIO::getSize() const {
{ if (!knownSize) {
if(!knownSize)
{
struct stat stbuf; struct stat stbuf;
memset(&stbuf, 0, sizeof(struct stat)); memset(&stbuf, 0, sizeof(struct stat));
int res = lstat(name.c_str(), &stbuf); int res = lstat(name.c_str(), &stbuf);
if(res == 0) if (res == 0) {
{
const_cast<RawFileIO *>(this)->fileSize = stbuf.st_size; const_cast<RawFileIO *>(this)->fileSize = stbuf.st_size;
const_cast<RawFileIO *>(this)->knownSize = true; const_cast<RawFileIO *>(this)->knownSize = true;
return fileSize; return fileSize;
} else } else
return -1; return -1;
} else } else {
{
return fileSize; return fileSize;
} }
} }
ssize_t RawFileIO::read( const IORequest &req ) const ssize_t RawFileIO::read(const IORequest &req) const {
{
rAssert(fd >= 0); rAssert(fd >= 0);
ssize_t readSize = pread(fd, req.data, req.dataLen, req.offset); ssize_t readSize = pread(fd, req.data, req.dataLen, req.offset);
if(readSize < 0) if (readSize < 0) {
{ rInfo("read failed at offset %" PRIi64 " for %i bytes: %s", req.offset,
rInfo("read failed at offset %" PRIi64 " for %i bytes: %s", req.dataLen, strerror(errno));
req.offset, req.dataLen, strerror( errno ));
} }
return readSize; return readSize;
} }
bool RawFileIO::write( const IORequest &req ) bool RawFileIO::write(const IORequest &req) {
{
rAssert(fd >= 0); rAssert(fd >= 0);
rAssert(true == canWrite); rAssert(true == canWrite);
@ -252,15 +209,13 @@ bool RawFileIO::write( const IORequest &req )
ssize_t bytes = req.dataLen; ssize_t bytes = req.dataLen;
off_t offset = req.offset; off_t offset = req.offset;
while( bytes && retrys > 0 ) while (bytes && retrys > 0) {
{
ssize_t writeSize = ::pwrite(fd, buf, bytes, offset); ssize_t writeSize = ::pwrite(fd, buf, bytes, offset);
if( writeSize < 0 ) if (writeSize < 0) {
{
knownSize = false; knownSize = false;
rInfo("write failed at offset %" PRIi64 " for %i bytes: %s", rInfo("write failed at offset %" PRIi64 " for %i bytes: %s", offset,
offset, (int)bytes, strerror( errno )); (int)bytes, strerror(errno));
return false; return false;
} }
@ -270,31 +225,25 @@ bool RawFileIO::write( const IORequest &req )
--retrys; --retrys;
} }
if(bytes != 0) if (bytes != 0) {
{
rError("Write error: wrote %i bytes of %i, max retries reached\n", rError("Write error: wrote %i bytes of %i, max retries reached\n",
(int)(req.dataLen - bytes), req.dataLen); (int)(req.dataLen - bytes), req.dataLen);
knownSize = false; knownSize = false;
return false; return false;
} else } else {
{ if (knownSize) {
if(knownSize)
{
off_t last = req.offset + req.dataLen; off_t last = req.offset + req.dataLen;
if(last > fileSize) if (last > fileSize) fileSize = last;
fileSize = last;
} }
return true; return true;
} }
} }
int RawFileIO::truncate( off_t size ) int RawFileIO::truncate(off_t size) {
{
int res; int res;
if(fd >= 0 && canWrite) if (fd >= 0 && canWrite) {
{
res = ::ftruncate(fd, size); res = ::ftruncate(fd, size);
#if !defined(__FreeBSD__) && !defined(__APPLE__) #if !defined(__FreeBSD__) && !defined(__APPLE__)
::fdatasync(fd); ::fdatasync(fd);
@ -302,15 +251,13 @@ int RawFileIO::truncate( off_t size )
} else } else
res = ::truncate(name.c_str(), size); res = ::truncate(name.c_str(), size);
if(res < 0) if (res < 0) {
{
int eno = errno; int eno = errno;
rInfo("truncate failed for %s (%i) size %" PRIi64 ", error %s", rInfo("truncate failed for %s (%i) size %" PRIi64 ", error %s",
name.c_str(), fd, size, strerror(eno)); name.c_str(), fd, size, strerror(eno));
res = -eno; res = -eno;
knownSize = false; knownSize = false;
} else } else {
{
res = 0; res = 0;
fileSize = size; fileSize = size;
knownSize = true; knownSize = true;
@ -319,7 +266,4 @@ int RawFileIO::truncate( off_t size )
return res; return res;
} }
bool RawFileIO::isWritable() const bool RawFileIO::isWritable() const { return canWrite; }
{
return canWrite;
}

View File

@ -25,8 +25,7 @@
#include <string> #include <string>
class RawFileIO : public FileIO class RawFileIO : public FileIO {
{
public: public:
RawFileIO(); RawFileIO();
RawFileIO(const std::string &fileName); RawFileIO(const std::string &fileName);
@ -48,8 +47,8 @@ public:
virtual int truncate(off_t size); virtual int truncate(off_t size);
virtual bool isWritable() const; virtual bool isWritable() const;
protected:
protected:
std::string name; std::string name;
bool knownSize; bool knownSize;
@ -61,4 +60,3 @@ protected:
}; };
#endif #endif

View File

@ -53,10 +53,7 @@ const int MAX_IVLENGTH = 16;
const int KEY_CHECKSUM_BYTES = 4; const int KEY_CHECKSUM_BYTES = 4;
#ifndef MIN #ifndef MIN
inline int MIN(int a, int b) inline int MIN(int a, int b) { return (a < b) ? a : b; }
{
return (a < b) ? a : b;
}
#endif #endif
/* /*
@ -71,9 +68,8 @@ inline int MIN(int a, int b)
password->data mappings, which is what the salt is meant to frustrate. password->data mappings, which is what the salt is meant to frustrate.
*/ */
int BytesToKey(int keyLen, int ivLen, const EVP_MD *md, int BytesToKey(int keyLen, int ivLen, const EVP_MD *md,
const unsigned char *data, int dataLen, const unsigned char *data, int dataLen, unsigned int rounds,
unsigned int rounds, unsigned char *key, unsigned char *iv) unsigned char *key, unsigned char *iv) {
{
if (data == NULL || dataLen == 0) if (data == NULL || dataLen == 0)
return 0; // OpenSSL returns nkey here, but why? It is a failure.. return 0; // OpenSSL returns nkey here, but why? It is a failure..
@ -86,16 +82,13 @@ int BytesToKey( int keyLen, int ivLen, const EVP_MD *md,
EVP_MD_CTX cx; EVP_MD_CTX cx;
EVP_MD_CTX_init(&cx); EVP_MD_CTX_init(&cx);
for(;;) for (;;) {
{
EVP_DigestInit_ex(&cx, md, NULL); EVP_DigestInit_ex(&cx, md, NULL);
if( addmd++ ) if (addmd++) EVP_DigestUpdate(&cx, mdBuf, mds);
EVP_DigestUpdate( &cx, mdBuf, mds );
EVP_DigestUpdate(&cx, data, dataLen); EVP_DigestUpdate(&cx, data, dataLen);
EVP_DigestFinal_ex(&cx, mdBuf, &mds); EVP_DigestFinal_ex(&cx, mdBuf, &mds);
for(unsigned int i=1; i < rounds; ++i) for (unsigned int i = 1; i < rounds; ++i) {
{
EVP_DigestInit_ex(&cx, md, NULL); EVP_DigestInit_ex(&cx, md, NULL);
EVP_DigestUpdate(&cx, mdBuf, mds); EVP_DigestUpdate(&cx, mdBuf, mds);
EVP_DigestFinal_ex(&cx, mdBuf, &mds); EVP_DigestFinal_ex(&cx, mdBuf, &mds);
@ -103,16 +96,14 @@ int BytesToKey( int keyLen, int ivLen, const EVP_MD *md,
int offset = 0; int offset = 0;
int toCopy = MIN(nkey, mds - offset); int toCopy = MIN(nkey, mds - offset);
if( toCopy ) if (toCopy) {
{
memcpy(key, mdBuf + offset, toCopy); memcpy(key, mdBuf + offset, toCopy);
key += toCopy; key += toCopy;
nkey -= toCopy; nkey -= toCopy;
offset += toCopy; offset += toCopy;
} }
toCopy = MIN(niv, mds - offset); toCopy = MIN(niv, mds - offset);
if( toCopy ) if (toCopy) {
{
memcpy(iv, mdBuf + offset, toCopy); memcpy(iv, mdBuf + offset, toCopy);
iv += toCopy; iv += toCopy;
niv -= toCopy; niv -= toCopy;
@ -126,46 +117,37 @@ int BytesToKey( int keyLen, int ivLen, const EVP_MD *md,
return keyLen; return keyLen;
} }
long time_diff(const timeval &end, const timeval &start) long time_diff(const timeval &end, const timeval &start) {
{
return (end.tv_sec - start.tv_sec) * 1000 * 1000 + return (end.tv_sec - start.tv_sec) * 1000 * 1000 +
(end.tv_usec - start.tv_usec); (end.tv_usec - start.tv_usec);
} }
int TimedPBKDF2(const char *pass, int passlen, int TimedPBKDF2(const char *pass, int passlen, const unsigned char *salt,
const unsigned char *salt, int saltlen, int saltlen, int keylen, unsigned char *out,
int keylen, unsigned char *out, long desiredPDFTime) {
long desiredPDFTime)
{
int iter = 1000; int iter = 1000;
timeval start, end; timeval start, end;
for(;;) for (;;) {
{
gettimeofday(&start, 0); gettimeofday(&start, 0);
int res = PKCS5_PBKDF2_HMAC_SHA1( int res =
pass, passlen, const_cast<unsigned char*>(salt), saltlen, PKCS5_PBKDF2_HMAC_SHA1(pass, passlen, const_cast<unsigned char *>(salt),
iter, keylen, out); saltlen, iter, keylen, out);
if(res != 1) if (res != 1) return -1;
return -1;
gettimeofday(&end, 0); gettimeofday(&end, 0);
long delta = time_diff(end, start); long delta = time_diff(end, start);
if(delta < desiredPDFTime / 8) if (delta < desiredPDFTime / 8) {
{
iter *= 4; iter *= 4;
} else if(delta < (5 * desiredPDFTime / 6)) } else if (delta < (5 * desiredPDFTime / 6)) {
{
// estimate number of iterations to get close to desired time // estimate number of iterations to get close to desired time
iter = (int)((double)iter * (double)desiredPDFTime iter = (int)((double)iter * (double)desiredPDFTime / (double)delta);
/ (double)delta);
} else } else
return iter; return iter;
} }
} }
// - Version 1:0 used EVP_BytesToKey, which didn't do the right thing for // - Version 1:0 used EVP_BytesToKey, which didn't do the right thing for
// Blowfish key lengths > 128 bit. // Blowfish key lengths > 128 bit.
// - Version 2:0 uses BytesToKey. // - Version 2:0 uses BytesToKey.
@ -181,44 +163,39 @@ static Interface AESInterface( "ssl/aes", 3, 0, 2 );
static Range BFKeyRange(128, 256, 32); static Range BFKeyRange(128, 256, 32);
static Range BFBlockRange(64, 4096, 8); static Range BFBlockRange(64, 4096, 8);
static shared_ptr<Cipher> NewBFCipher( const Interface &iface, int keyLen ) static shared_ptr<Cipher> NewBFCipher(const Interface &iface, int keyLen) {
{ if (keyLen <= 0) keyLen = 160;
if( keyLen <= 0 )
keyLen = 160;
keyLen = BFKeyRange.closest(keyLen); keyLen = BFKeyRange.closest(keyLen);
const EVP_CIPHER *blockCipher = EVP_bf_cbc(); const EVP_CIPHER *blockCipher = EVP_bf_cbc();
const EVP_CIPHER *streamCipher = EVP_bf_cfb(); const EVP_CIPHER *streamCipher = EVP_bf_cfb();
return shared_ptr<Cipher>( new SSL_Cipher(iface, BlowfishInterface, return shared_ptr<Cipher>(new SSL_Cipher(
blockCipher, streamCipher, keyLen / 8) ); iface, BlowfishInterface, blockCipher, streamCipher, keyLen / 8));
} }
static bool BF_Cipher_registered = Cipher::Register("Blowfish", static bool BF_Cipher_registered =
Cipher::Register("Blowfish",
// xgroup(setup) // xgroup(setup)
gettext_noop("8 byte block cipher"), gettext_noop("8 byte block cipher"), BlowfishInterface,
BlowfishInterface, BFKeyRange, BFBlockRange, NewBFCipher); BFKeyRange, BFBlockRange, NewBFCipher);
#endif #endif
#if defined(HAVE_EVP_AES) #if defined(HAVE_EVP_AES)
static Range AESKeyRange(128, 256, 64); static Range AESKeyRange(128, 256, 64);
static Range AESBlockRange(64, 4096, 16); static Range AESBlockRange(64, 4096, 16);
static shared_ptr<Cipher> NewAESCipher( const Interface &iface, int keyLen ) static shared_ptr<Cipher> NewAESCipher(const Interface &iface, int keyLen) {
{ if (keyLen <= 0) keyLen = 192;
if( keyLen <= 0 )
keyLen = 192;
keyLen = AESKeyRange.closest(keyLen); keyLen = AESKeyRange.closest(keyLen);
const EVP_CIPHER *blockCipher = 0; const EVP_CIPHER *blockCipher = 0;
const EVP_CIPHER *streamCipher = 0; const EVP_CIPHER *streamCipher = 0;
switch(keyLen) switch (keyLen) {
{
case 128: case 128:
blockCipher = EVP_aes_128_cbc(); blockCipher = EVP_aes_128_cbc();
streamCipher = EVP_aes_128_cfb(); streamCipher = EVP_aes_128_cfb();
@ -236,17 +213,16 @@ static shared_ptr<Cipher> NewAESCipher( const Interface &iface, int keyLen )
break; break;
} }
return shared_ptr<Cipher>( new SSL_Cipher(iface, AESInterface, return shared_ptr<Cipher>(new SSL_Cipher(iface, AESInterface, blockCipher,
blockCipher, streamCipher, keyLen / 8) ); streamCipher, keyLen / 8));
} }
static bool AES_Cipher_registered = Cipher::Register("AES", static bool AES_Cipher_registered =
"16 byte block cipher", Cipher::Register("AES", "16 byte block cipher", AESInterface, AESKeyRange,
AESInterface, AESKeyRange, AESBlockRange, NewAESCipher); AESBlockRange, NewAESCipher);
#endif #endif
class SSLKey : public AbstractCipherKey class SSLKey : public AbstractCipherKey {
{
public: public:
pthread_mutex_t mutex; pthread_mutex_t mutex;
@ -268,8 +244,7 @@ public:
~SSLKey(); ~SSLKey();
}; };
SSLKey::SSLKey(int keySize_, int ivLength_) SSLKey::SSLKey(int keySize_, int ivLength_) {
{
this->keySize = keySize_; this->keySize = keySize_;
this->ivLength = ivLength_; this->ivLength = ivLength_;
pthread_mutex_init(&mutex, 0); pthread_mutex_init(&mutex, 0);
@ -281,8 +256,7 @@ SSLKey::SSLKey(int keySize_, int ivLength_)
mlock(buffer, keySize + ivLength); mlock(buffer, keySize + ivLength);
} }
SSLKey::~SSLKey() SSLKey::~SSLKey() {
{
memset(buffer, 0, keySize + ivLength); memset(buffer, 0, keySize + ivLength);
OPENSSL_free(buffer); OPENSSL_free(buffer);
@ -302,19 +276,15 @@ SSLKey::~SSLKey()
pthread_mutex_destroy(&mutex); pthread_mutex_destroy(&mutex);
} }
inline unsigned char *KeyData(const shared_ptr<SSLKey> &key) {
inline unsigned char* KeyData( const shared_ptr<SSLKey> &key )
{
return key->buffer; return key->buffer;
} }
inline unsigned char* IVData( const shared_ptr<SSLKey> &key ) inline unsigned char *IVData(const shared_ptr<SSLKey> &key) {
{
return key->buffer + key->keySize; return key->buffer + key->keySize;
} }
void initKey(const shared_ptr<SSLKey> &key, const EVP_CIPHER *_blockCipher, void initKey(const shared_ptr<SSLKey> &key, const EVP_CIPHER *_blockCipher,
const EVP_CIPHER *_streamCipher, int _keySize) const EVP_CIPHER *_streamCipher, int _keySize) {
{
Lock lock(key->mutex); Lock lock(key->mutex);
// initialize the cipher context once so that we don't have to do it for // initialize the cipher context once so that we don't have to do it for
// every block.. // every block..
@ -347,15 +317,11 @@ void initKey(const shared_ptr<SSLKey> &key, const EVP_CIPHER *_blockCipher,
HMAC_Init_ex(&key->mac_ctx, KeyData(key), _keySize, EVP_sha1(), 0); HMAC_Init_ex(&key->mac_ctx, KeyData(key), _keySize, EVP_sha1(), 0);
} }
static RLogChannel *CipherInfo = DEF_CHANNEL("info/cipher", Log_Info); static RLogChannel *CipherInfo = DEF_CHANNEL("info/cipher", Log_Info);
SSL_Cipher::SSL_Cipher(const Interface &iface_, SSL_Cipher::SSL_Cipher(const Interface &iface_, const Interface &realIface_,
const Interface &realIface_,
const EVP_CIPHER *blockCipher, const EVP_CIPHER *blockCipher,
const EVP_CIPHER *streamCipher, const EVP_CIPHER *streamCipher, int keySize_) {
int keySize_)
{
this->iface = iface_; this->iface = iface_;
this->realIface = realIface_; this->realIface = realIface_;
this->_blockCipher = blockCipher; this->_blockCipher = blockCipher;
@ -368,25 +334,19 @@ SSL_Cipher::SSL_Cipher(const Interface &iface_,
rLog(CipherInfo, "allocated cipher %s, keySize %i, ivlength %i", rLog(CipherInfo, "allocated cipher %s, keySize %i, ivlength %i",
iface.name().c_str(), _keySize, _ivLength); iface.name().c_str(), _keySize, _ivLength);
if( (EVP_CIPHER_key_length( _blockCipher ) != (int )_keySize) if ((EVP_CIPHER_key_length(_blockCipher) != (int)_keySize) &&
&& iface.current() == 1) iface.current() == 1) {
{ rWarning(
rWarning("Running in backward compatibilty mode for 1.0 - \n" "Running in backward compatibilty mode for 1.0 - \n"
"key is really %i bits, not %i.\n" "key is really %i bits, not %i.\n"
"Consider creating a new filesystem and moving your data.", "Consider creating a new filesystem and moving your data.",
EVP_CIPHER_key_length( _blockCipher ) * 8, EVP_CIPHER_key_length(_blockCipher) * 8, _keySize * 8);
_keySize * 8 );
} }
} }
SSL_Cipher::~SSL_Cipher() SSL_Cipher::~SSL_Cipher() {}
{
}
Interface SSL_Cipher::interface() const Interface SSL_Cipher::interface() const { return realIface; }
{
return realIface;
}
/* /*
create a key from the password. create a key from the password.
@ -397,31 +357,24 @@ Interface SSL_Cipher::interface() const
*/ */
CipherKey SSL_Cipher::newKey(const char *password, int passwdLength, CipherKey SSL_Cipher::newKey(const char *password, int passwdLength,
int &iterationCount, long desiredDuration, int &iterationCount, long desiredDuration,
const unsigned char *salt, int saltLen) const unsigned char *salt, int saltLen) {
{
shared_ptr<SSLKey> key(new SSLKey(_keySize, _ivLength)); shared_ptr<SSLKey> key(new SSLKey(_keySize, _ivLength));
if(iterationCount == 0) if (iterationCount == 0) {
{
// timed run, fills in iteration count // timed run, fills in iteration count
int res = TimedPBKDF2(password, passwdLength, int res =
salt, saltLen, TimedPBKDF2(password, passwdLength, salt, saltLen, _keySize + _ivLength,
_keySize+_ivLength, KeyData(key), KeyData(key), 1000 * desiredDuration);
1000 * desiredDuration); if (res <= 0) {
if(res <= 0)
{
rWarning("openssl error, PBKDF2 failed"); rWarning("openssl error, PBKDF2 failed");
return CipherKey(); return CipherKey();
} else } else
iterationCount = res; iterationCount = res;
} else } else {
{
// known iteration length // known iteration length
if (PKCS5_PBKDF2_HMAC_SHA1( if (PKCS5_PBKDF2_HMAC_SHA1(
password, passwdLength, password, passwdLength, const_cast<unsigned char *>(salt), saltLen,
const_cast<unsigned char*>(salt), saltLen, iterationCount, _keySize + _ivLength, KeyData(key)) != 1) {
iterationCount, _keySize + _ivLength, KeyData(key)) != 1)
{
rWarning("openssl error, PBKDF2 failed"); rWarning("openssl error, PBKDF2 failed");
return CipherKey(); return CipherKey();
} }
@ -432,27 +385,23 @@ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength,
return key; return key;
} }
CipherKey SSL_Cipher::newKey(const char *password, int passwdLength) CipherKey SSL_Cipher::newKey(const char *password, int passwdLength) {
{
shared_ptr<SSLKey> key(new SSLKey(_keySize, _ivLength)); shared_ptr<SSLKey> key(new SSLKey(_keySize, _ivLength));
int bytes = 0; int bytes = 0;
if( iface.current() > 1 ) if (iface.current() > 1) {
{
// now we use BytesToKey, which can deal with Blowfish keys larger then // now we use BytesToKey, which can deal with Blowfish keys larger then
// 128 bits. // 128 bits.
bytes = BytesToKey( _keySize, _ivLength, EVP_sha1(), bytes =
(unsigned char *)password, passwdLength, 16, BytesToKey(_keySize, _ivLength, EVP_sha1(), (unsigned char *)password,
KeyData(key), IVData(key) ); passwdLength, 16, KeyData(key), IVData(key));
// the reason for moving from EVP_BytesToKey to BytesToKey function.. // the reason for moving from EVP_BytesToKey to BytesToKey function..
if(bytes != (int)_keySize) if (bytes != (int)_keySize) {
{ rWarning("newKey: BytesToKey returned %i, expecting %i key bytes", bytes,
rWarning("newKey: BytesToKey returned %i, expecting %i key bytes", _keySize);
bytes, _keySize);
} }
} else } else {
{
// for backward compatibility with filesystems created with 1:0 // for backward compatibility with filesystems created with 1:0
bytes = EVP_BytesToKey(_blockCipher, EVP_sha1(), NULL, bytes = EVP_BytesToKey(_blockCipher, EVP_sha1(), NULL,
(unsigned char *)password, passwdLength, 16, (unsigned char *)password, passwdLength, 16,
@ -472,24 +421,21 @@ CipherKey SSL_Cipher::newKey(const char *password, int passwdLength)
This algorithm can change at any time without affecting backward This algorithm can change at any time without affecting backward
compatibility. compatibility.
*/ */
CipherKey SSL_Cipher::newRandomKey() CipherKey SSL_Cipher::newRandomKey() {
{
const int bufLen = MAX_KEYLENGTH; const int bufLen = MAX_KEYLENGTH;
unsigned char tmpBuf[bufLen]; unsigned char tmpBuf[bufLen];
int saltLen = 20; int saltLen = 20;
unsigned char saltBuf[saltLen]; unsigned char saltBuf[saltLen];
if(!randomize(tmpBuf, bufLen, true) || if (!randomize(tmpBuf, bufLen, true) || !randomize(saltBuf, saltLen, true))
!randomize(saltBuf, saltLen, true))
return CipherKey(); return CipherKey();
shared_ptr<SSLKey> key(new SSLKey(_keySize, _ivLength)); shared_ptr<SSLKey> key(new SSLKey(_keySize, _ivLength));
// doesn't need to be versioned, because a random key is a random key.. // doesn't need to be versioned, because a random key is a random key..
// Doesn't need to be reproducable.. // Doesn't need to be reproducable..
if(PKCS5_PBKDF2_HMAC_SHA1((char*)tmpBuf, bufLen, saltBuf, saltLen, if (PKCS5_PBKDF2_HMAC_SHA1((char *)tmpBuf, bufLen, saltBuf, saltLen, 1000,
1000, _keySize + _ivLength, KeyData(key)) != 1) _keySize + _ivLength, KeyData(key)) != 1) {
{
rWarning("openssl error, PBKDF2 failed"); rWarning("openssl error, PBKDF2 failed");
return CipherKey(); return CipherKey();
} }
@ -504,9 +450,8 @@ CipherKey SSL_Cipher::newRandomKey()
/* /*
compute a 64-bit check value for the data using HMAC. compute a 64-bit check value for the data using HMAC.
*/ */
static uint64_t _checksum_64( SSLKey *key, static uint64_t _checksum_64(SSLKey *key, const unsigned char *data,
const unsigned char *data, int dataLen, uint64_t *chainedIV) int dataLen, uint64_t *chainedIV) {
{
rAssert(dataLen > 0); rAssert(dataLen > 0);
Lock lock(key->mutex); Lock lock(key->mutex);
@ -515,13 +460,11 @@ static uint64_t _checksum_64( SSLKey *key,
HMAC_Init_ex(&key->mac_ctx, 0, 0, 0, 0); HMAC_Init_ex(&key->mac_ctx, 0, 0, 0, 0);
HMAC_Update(&key->mac_ctx, data, dataLen); HMAC_Update(&key->mac_ctx, data, dataLen);
if(chainedIV) if (chainedIV) {
{
// toss in the chained IV as well // toss in the chained IV as well
uint64_t tmp = *chainedIV; uint64_t tmp = *chainedIV;
unsigned char h[8]; unsigned char h[8];
for(unsigned int i=0; i<8; ++i) for (unsigned int i = 0; i < 8; ++i) {
{
h[i] = tmp & 0xff; h[i] = tmp & 0xff;
tmp >>= 8; tmp >>= 8;
} }
@ -539,15 +482,13 @@ static uint64_t _checksum_64( SSLKey *key,
h[i % 8] ^= (unsigned char)(md[i]); h[i % 8] ^= (unsigned char)(md[i]);
uint64_t value = (uint64_t)h[0]; uint64_t value = (uint64_t)h[0];
for(int i=1; i<8; ++i) for (int i = 1; i < 8; ++i) value = (value << 8) | (uint64_t)h[i];
value = (value << 8) | (uint64_t)h[i];
return value; return value;
} }
bool SSL_Cipher::randomize(unsigned char *buf, int len, bool SSL_Cipher::randomize(unsigned char *buf, int len,
bool strongRandom ) const bool strongRandom) const {
{
// to avoid warnings of uninitialized data from valgrind // to avoid warnings of uninitialized data from valgrind
memset(buf, 0, len); memset(buf, 0, len);
int result; int result;
@ -556,8 +497,7 @@ bool SSL_Cipher::randomize( unsigned char *buf, int len,
else else
result = RAND_pseudo_bytes(buf, len); result = RAND_pseudo_bytes(buf, len);
if(result != 1) if (result != 1) {
{
char errStr[120]; // specs require string at least 120 bytes long.. char errStr[120]; // specs require string at least 120 bytes long..
unsigned long errVal = 0; unsigned long errVal = 0;
if ((errVal = ERR_get_error()) != 0) if ((errVal = ERR_get_error()) != 0)
@ -569,20 +509,17 @@ bool SSL_Cipher::randomize( unsigned char *buf, int len,
} }
uint64_t SSL_Cipher::MAC_64(const unsigned char *data, int len, uint64_t SSL_Cipher::MAC_64(const unsigned char *data, int len,
const CipherKey &key, uint64_t *chainedIV ) const const CipherKey &key, uint64_t *chainedIV) const {
{
shared_ptr<SSLKey> mk = dynamic_pointer_cast<SSLKey>(key); shared_ptr<SSLKey> mk = dynamic_pointer_cast<SSLKey>(key);
uint64_t tmp = _checksum_64(mk.get(), data, len, chainedIV); uint64_t tmp = _checksum_64(mk.get(), data, len, chainedIV);
if(chainedIV) if (chainedIV) *chainedIV = tmp;
*chainedIV = tmp;
return tmp; return tmp;
} }
CipherKey SSL_Cipher::readKey(const unsigned char *data, CipherKey SSL_Cipher::readKey(const unsigned char *data,
const CipherKey &masterKey, bool checkKey) const CipherKey &masterKey, bool checkKey) {
{
shared_ptr<SSLKey> mk = dynamic_pointer_cast<SSLKey>(masterKey); shared_ptr<SSLKey> mk = dynamic_pointer_cast<SSLKey>(masterKey);
rAssert(mk->keySize == _keySize); rAssert(mk->keySize == _keySize);
@ -598,8 +535,7 @@ CipherKey SSL_Cipher::readKey(const unsigned char *data,
// check for success // check for success
unsigned int checksum2 = MAC_32(tmpBuf, _keySize + _ivLength, masterKey); unsigned int checksum2 = MAC_32(tmpBuf, _keySize + _ivLength, masterKey);
if(checksum2 != checksum && checkKey) if (checksum2 != checksum && checkKey) {
{
rDebug("checksum mismatch: expected %u, got %u", checksum, checksum2); rDebug("checksum mismatch: expected %u, got %u", checksum, checksum2);
rDebug("on decode of %i bytes", _keySize + _ivLength); rDebug("on decode of %i bytes", _keySize + _ivLength);
memset(tmpBuf, 0, sizeof(tmpBuf)); memset(tmpBuf, 0, sizeof(tmpBuf));
@ -617,8 +553,7 @@ CipherKey SSL_Cipher::readKey(const unsigned char *data,
} }
void SSL_Cipher::writeKey(const CipherKey &ckey, unsigned char *data, void SSL_Cipher::writeKey(const CipherKey &ckey, unsigned char *data,
const CipherKey &masterKey) const CipherKey &masterKey) {
{
shared_ptr<SSLKey> key = dynamic_pointer_cast<SSLKey>(ckey); shared_ptr<SSLKey> key = dynamic_pointer_cast<SSLKey>(ckey);
rAssert(key->keySize == _keySize); rAssert(key->keySize == _keySize);
rAssert(key->ivLength == _ivLength); rAssert(key->ivLength == _ivLength);
@ -638,8 +573,7 @@ void SSL_Cipher::writeKey(const CipherKey &ckey, unsigned char *data,
memcpy(data + KEY_CHECKSUM_BYTES, tmpBuf, bufLen); memcpy(data + KEY_CHECKSUM_BYTES, tmpBuf, bufLen);
// first N bytes contain HMAC derived checksum.. // first N bytes contain HMAC derived checksum..
for(int i=1; i<=KEY_CHECKSUM_BYTES; ++i) for (int i = 1; i <= KEY_CHECKSUM_BYTES; ++i) {
{
data[KEY_CHECKSUM_BYTES - i] = checksum & 0xff; data[KEY_CHECKSUM_BYTES - i] = checksum & 0xff;
checksum >>= 8; checksum >>= 8;
} }
@ -647,8 +581,7 @@ void SSL_Cipher::writeKey(const CipherKey &ckey, unsigned char *data,
memset(tmpBuf, 0, sizeof(tmpBuf)); memset(tmpBuf, 0, sizeof(tmpBuf));
} }
bool SSL_Cipher::compareKey( const CipherKey &A, const CipherKey &B) const bool SSL_Cipher::compareKey(const CipherKey &A, const CipherKey &B) const {
{
shared_ptr<SSLKey> key1 = dynamic_pointer_cast<SSLKey>(A); shared_ptr<SSLKey> key1 = dynamic_pointer_cast<SSLKey>(A);
shared_ptr<SSLKey> key2 = dynamic_pointer_cast<SSLKey>(B); shared_ptr<SSLKey> key2 = dynamic_pointer_cast<SSLKey>(B);
@ -661,33 +594,25 @@ bool SSL_Cipher::compareKey( const CipherKey &A, const CipherKey &B) const
return true; return true;
} }
int SSL_Cipher::encodedKeySize() const int SSL_Cipher::encodedKeySize() const {
{
return _keySize + _ivLength + KEY_CHECKSUM_BYTES; return _keySize + _ivLength + KEY_CHECKSUM_BYTES;
} }
int SSL_Cipher::keySize() const int SSL_Cipher::keySize() const { return _keySize; }
{
return _keySize;
}
int SSL_Cipher::cipherBlockSize() const int SSL_Cipher::cipherBlockSize() const {
{
return EVP_CIPHER_block_size(_blockCipher); return EVP_CIPHER_block_size(_blockCipher);
} }
void SSL_Cipher::setIVec(unsigned char *ivec, uint64_t seed, void SSL_Cipher::setIVec(unsigned char *ivec, uint64_t seed,
const shared_ptr<SSLKey> &key) const const shared_ptr<SSLKey> &key) const {
{ if (iface.current() >= 3) {
if (iface.current() >= 3)
{
memcpy(ivec, IVData(key), _ivLength); memcpy(ivec, IVData(key), _ivLength);
unsigned char md[EVP_MAX_MD_SIZE]; unsigned char md[EVP_MAX_MD_SIZE];
unsigned int mdLen = EVP_MAX_MD_SIZE; unsigned int mdLen = EVP_MAX_MD_SIZE;
for(int i=0; i<8; ++i) for (int i = 0; i < 8; ++i) {
{
md[i] = (unsigned char)(seed & 0xff); md[i] = (unsigned char)(seed & 0xff);
seed >>= 8; seed >>= 8;
} }
@ -700,8 +625,7 @@ void SSL_Cipher::setIVec( unsigned char *ivec, uint64_t seed,
rAssert(mdLen >= _ivLength); rAssert(mdLen >= _ivLength);
memcpy(ivec, md, _ivLength); memcpy(ivec, md, _ivLength);
} else } else {
{
setIVec_old(ivec, seed, key); setIVec_old(ivec, seed, key);
} }
} }
@ -712,10 +636,8 @@ void SSL_Cipher::setIVec( unsigned char *ivec, uint64_t seed,
determine if the victim had the file in encrypted storage (without determine if the victim had the file in encrypted storage (without
decrypting the file). decrypting the file).
*/ */
void SSL_Cipher::setIVec_old(unsigned char *ivec, void SSL_Cipher::setIVec_old(unsigned char *ivec, unsigned int seed,
unsigned int seed, const shared_ptr<SSLKey> &key) const {
const shared_ptr<SSLKey> &key) const
{
/* These multiplication constants chosen as they represent (non optimal) /* These multiplication constants chosen as they represent (non optimal)
Golumb rulers, the idea being to spread around the information in the Golumb rulers, the idea being to spread around the information in the
seed. seed.
@ -737,8 +659,7 @@ void SSL_Cipher::setIVec_old(unsigned char *ivec,
ivec[6] ^= (var2 >> 8) & 0xff; ivec[6] ^= (var2 >> 8) & 0xff;
ivec[7] ^= (var1) & 0xff; ivec[7] ^= (var1) & 0xff;
if(_ivLength > 8) if (_ivLength > 8) {
{
ivec[8 + 0] ^= (var1) & 0xff; ivec[8 + 0] ^= (var1) & 0xff;
ivec[8 + 1] ^= (var2 >> 8) & 0xff; ivec[8 + 1] ^= (var2 >> 8) & 0xff;
ivec[8 + 2] ^= (var1 >> 16) & 0xff; ivec[8 + 2] ^= (var1 >> 16) & 0xff;
@ -750,17 +671,14 @@ void SSL_Cipher::setIVec_old(unsigned char *ivec,
} }
} }
static void flipBytes(unsigned char *buf, int size) static void flipBytes(unsigned char *buf, int size) {
{
unsigned char revBuf[64]; unsigned char revBuf[64];
int bytesLeft = size; int bytesLeft = size;
while(bytesLeft) while (bytesLeft) {
{
int toFlip = MIN(sizeof(revBuf), bytesLeft); int toFlip = MIN(sizeof(revBuf), bytesLeft);
for(int i=0; i<toFlip; ++i) for (int i = 0; i < toFlip; ++i) revBuf[i] = buf[toFlip - (i + 1)];
revBuf[i] = buf[toFlip - (i+1)];
memcpy(buf, revBuf, toFlip); memcpy(buf, revBuf, toFlip);
bytesLeft -= toFlip; bytesLeft -= toFlip;
@ -769,24 +687,19 @@ static void flipBytes(unsigned char *buf, int size)
memset(revBuf, 0, sizeof(revBuf)); memset(revBuf, 0, sizeof(revBuf));
} }
static void shuffleBytes(unsigned char *buf, int size) static void shuffleBytes(unsigned char *buf, int size) {
{ for (int i = 0; i < size - 1; ++i) buf[i + 1] ^= buf[i];
for(int i=0; i<size-1; ++i)
buf[i+1] ^= buf[i];
} }
static void unshuffleBytes(unsigned char *buf, int size) static void unshuffleBytes(unsigned char *buf, int size) {
{ for (int i = size - 1; i; --i) buf[i] ^= buf[i - 1];
for(int i=size-1; i; --i)
buf[i] ^= buf[i-1];
} }
/* Partial blocks are encoded with a stream cipher. We make multiple passes on /* Partial blocks are encoded with a stream cipher. We make multiple passes on
the data to ensure that the ends of the data depend on each other. the data to ensure that the ends of the data depend on each other.
*/ */
bool SSL_Cipher::streamEncode(unsigned char *buf, int size, bool SSL_Cipher::streamEncode(unsigned char *buf, int size, uint64_t iv64,
uint64_t iv64, const CipherKey &ckey) const const CipherKey &ckey) const {
{
rAssert(size > 0); rAssert(size > 0);
shared_ptr<SSLKey> key = dynamic_pointer_cast<SSLKey>(ckey); shared_ptr<SSLKey> key = dynamic_pointer_cast<SSLKey>(ckey);
rAssert(key->keySize == _keySize); rAssert(key->keySize == _keySize);
@ -813,18 +726,16 @@ bool SSL_Cipher::streamEncode(unsigned char *buf, int size,
EVP_EncryptFinal_ex(&key->stream_enc, buf + dstLen, &tmpLen); EVP_EncryptFinal_ex(&key->stream_enc, buf + dstLen, &tmpLen);
dstLen += tmpLen; dstLen += tmpLen;
if(dstLen != size) if (dstLen != size) {
{ rError("encoding %i bytes, got back %i (%i in final_ex)", size, dstLen,
rError("encoding %i bytes, got back %i (%i in final_ex)", tmpLen);
size, dstLen, tmpLen);
} }
return true; return true;
} }
bool SSL_Cipher::streamDecode(unsigned char *buf, int size, bool SSL_Cipher::streamDecode(unsigned char *buf, int size, uint64_t iv64,
uint64_t iv64, const CipherKey &ckey) const const CipherKey &ckey) const {
{
rAssert(size > 0); rAssert(size > 0);
shared_ptr<SSLKey> key = dynamic_pointer_cast<SSLKey>(ckey); shared_ptr<SSLKey> key = dynamic_pointer_cast<SSLKey>(ckey);
rAssert(key->keySize == _keySize); rAssert(key->keySize == _keySize);
@ -851,19 +762,16 @@ bool SSL_Cipher::streamDecode(unsigned char *buf, int size,
unshuffleBytes(buf, size); unshuffleBytes(buf, size);
dstLen += tmpLen; dstLen += tmpLen;
if(dstLen != size) if (dstLen != size) {
{ rError("encoding %i bytes, got back %i (%i in final_ex)", size, dstLen,
rError("encoding %i bytes, got back %i (%i in final_ex)", tmpLen);
size, dstLen, tmpLen);
} }
return true; return true;
} }
bool SSL_Cipher::blockEncode(unsigned char *buf, int size, uint64_t iv64,
bool SSL_Cipher::blockEncode(unsigned char *buf, int size, const CipherKey &ckey) const {
uint64_t iv64, const CipherKey &ckey ) const
{
rAssert(size > 0); rAssert(size > 0);
shared_ptr<SSLKey> key = dynamic_pointer_cast<SSLKey>(ckey); shared_ptr<SSLKey> key = dynamic_pointer_cast<SSLKey>(ckey);
rAssert(key->keySize == _keySize); rAssert(key->keySize == _keySize);
@ -886,18 +794,16 @@ bool SSL_Cipher::blockEncode(unsigned char *buf, int size,
EVP_EncryptFinal_ex(&key->block_enc, buf + dstLen, &tmpLen); EVP_EncryptFinal_ex(&key->block_enc, buf + dstLen, &tmpLen);
dstLen += tmpLen; dstLen += tmpLen;
if(dstLen != size) if (dstLen != size) {
{ rError("encoding %i bytes, got back %i (%i in final_ex)", size, dstLen,
rError("encoding %i bytes, got back %i (%i in final_ex)", tmpLen);
size, dstLen, tmpLen);
} }
return true; return true;
} }
bool SSL_Cipher::blockDecode(unsigned char *buf, int size, bool SSL_Cipher::blockDecode(unsigned char *buf, int size, uint64_t iv64,
uint64_t iv64, const CipherKey &ckey ) const const CipherKey &ckey) const {
{
rAssert(size > 0); rAssert(size > 0);
shared_ptr<SSLKey> key = dynamic_pointer_cast<SSLKey>(ckey); shared_ptr<SSLKey> key = dynamic_pointer_cast<SSLKey>(ckey);
rAssert(key->keySize == _keySize); rAssert(key->keySize == _keySize);
@ -920,17 +826,12 @@ bool SSL_Cipher::blockDecode(unsigned char *buf, int size,
EVP_DecryptFinal_ex(&key->block_dec, buf + dstLen, &tmpLen); EVP_DecryptFinal_ex(&key->block_dec, buf + dstLen, &tmpLen);
dstLen += tmpLen; dstLen += tmpLen;
if(dstLen != size) if (dstLen != size) {
{ rError("decoding %i bytes, got back %i (%i in final_ex)", size, dstLen,
rError("decoding %i bytes, got back %i (%i in final_ex)", tmpLen);
size, dstLen, tmpLen);
} }
return true; return true;
} }
bool SSL_Cipher::Enabled() bool SSL_Cipher::Enabled() { return true; }
{
return true;
}

View File

@ -68,8 +68,7 @@ typedef struct evp_cipher_st EVP_CIPHER;
initial value vector to randomize the output. But it makes the code initial value vector to randomize the output. But it makes the code
simpler to reuse the encryption algorithm as is. simpler to reuse the encryption algorithm as is.
*/ */
class SSL_Cipher : public Cipher class SSL_Cipher : public Cipher {
{
rel::Interface iface; rel::Interface iface;
rel::Interface realIface; rel::Interface realIface;
const EVP_CIPHER *_blockCipher; const EVP_CIPHER *_blockCipher;
@ -97,20 +96,17 @@ public:
// data must be len keySize() // data must be len keySize()
virtual CipherKey readKey(const unsigned char *data, virtual CipherKey readKey(const unsigned char *data,
const CipherKey &encodingKey, const CipherKey &encodingKey, bool checkKey);
bool checkKey);
virtual void writeKey(const CipherKey &key, unsigned char *data, virtual void writeKey(const CipherKey &key, unsigned char *data,
const CipherKey &encodingKey); const CipherKey &encodingKey);
virtual bool compareKey( const CipherKey &A, virtual bool compareKey(const CipherKey &A, const CipherKey &B) const;
const CipherKey &B ) const;
// meta-data about the cypher // meta-data about the cypher
virtual int keySize() const; virtual int keySize() const;
virtual int encodedKeySize() const; virtual int encodedKeySize() const;
virtual int cipherBlockSize() const; virtual int cipherBlockSize() const;
virtual bool randomize( unsigned char *buf, int len, virtual bool randomize(unsigned char *buf, int len, bool strongRandom) const;
bool strongRandom ) const;
virtual uint64_t MAC_64(const unsigned char *src, int len, virtual uint64_t MAC_64(const unsigned char *src, int len,
const CipherKey &key, uint64_t *augment) const; const CipherKey &key, uint64_t *augment) const;
@ -119,23 +115,24 @@ public:
/* /*
Stream encoding in-place. Stream encoding in-place.
*/ */
virtual bool streamEncode(unsigned char *in, int len, virtual bool streamEncode(unsigned char *in, int len, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const; const CipherKey &key) const;
virtual bool streamDecode(unsigned char *in, int len, virtual bool streamDecode(unsigned char *in, int len, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const; const CipherKey &key) const;
/* /*
Block encoding is done in-place. Partial blocks are supported, but Block encoding is done in-place. Partial blocks are supported, but
blocks are always expected to begin on a block boundary. See blocks are always expected to begin on a block boundary. See
blockSize(). blockSize().
*/ */
virtual bool blockEncode(unsigned char *buf, int size, virtual bool blockEncode(unsigned char *buf, int size, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const; const CipherKey &key) const;
virtual bool blockDecode(unsigned char *buf, int size, virtual bool blockDecode(unsigned char *buf, int size, uint64_t iv64,
uint64_t iv64, const CipherKey &key) const; const CipherKey &key) const;
// hack to help with static builds // hack to help with static builds
static bool Enabled(); static bool Enabled();
private: private:
void setIVec(unsigned char *ivec, uint64_t seed, void setIVec(unsigned char *ivec, uint64_t seed,
const shared_ptr<SSLKey> &key) const; const shared_ptr<SSLKey> &key) const;
@ -145,6 +142,4 @@ private:
const shared_ptr<SSLKey> &key) const; const shared_ptr<SSLKey> &key) const;
}; };
#endif #endif

View File

@ -33,16 +33,15 @@ using namespace rel;
using namespace std; using namespace std;
static shared_ptr<NameIO> NewStreamNameIO(const Interface &iface, static shared_ptr<NameIO> NewStreamNameIO(const Interface &iface,
const shared_ptr<Cipher> &cipher, const CipherKey &key) const shared_ptr<Cipher> &cipher,
{ const CipherKey &key) {
return shared_ptr<NameIO>(new StreamNameIO(iface, cipher, key)); return shared_ptr<NameIO>(new StreamNameIO(iface, cipher, key));
} }
static bool StreamIO_registered = NameIO::Register("Stream", static bool StreamIO_registered = NameIO::Register(
"Stream",
gettext_noop("Stream encoding, keeps filenames as short as possible"), gettext_noop("Stream encoding, keeps filenames as short as possible"),
StreamNameIO::CurrentInterface(), StreamNameIO::CurrentInterface(), NewStreamNameIO);
NewStreamNameIO);
/* /*
- Version 0.1 is for EncFS 0.x support. The difference to 1.0 is that 0.x - Version 0.1 is for EncFS 0.x support. The difference to 1.0 is that 0.x
@ -65,8 +64,7 @@ static bool StreamIO_registered = NameIO::Register("Stream",
- Version 2.1 adds support for version 0 for EncFS 0.x compatibility. - Version 2.1 adds support for version 0 for EncFS 0.x compatibility.
*/ */
Interface StreamNameIO::CurrentInterface() Interface StreamNameIO::CurrentInterface() {
{
// implement major version 2, 1, and 0 // implement major version 2, 1, and 0
return Interface("nameio/stream", 2, 1, 2); return Interface("nameio/stream", 2, 1, 2);
} }
@ -74,54 +72,38 @@ Interface StreamNameIO::CurrentInterface()
StreamNameIO::StreamNameIO(const rel::Interface &iface, StreamNameIO::StreamNameIO(const rel::Interface &iface,
const shared_ptr<Cipher> &cipher, const shared_ptr<Cipher> &cipher,
const CipherKey &key) const CipherKey &key)
: _interface( iface.current() ) : _interface(iface.current()), _cipher(cipher), _key(key) {}
, _cipher( cipher )
, _key( key )
{
} StreamNameIO::~StreamNameIO() {}
StreamNameIO::~StreamNameIO() Interface StreamNameIO::interface() const { return CurrentInterface(); }
{
}
Interface StreamNameIO::interface() const int StreamNameIO::maxEncodedNameLen(int plaintextStreamLen) const {
{
return CurrentInterface();
}
int StreamNameIO::maxEncodedNameLen( int plaintextStreamLen ) const
{
int encodedStreamLen = 2 + plaintextStreamLen; int encodedStreamLen = 2 + plaintextStreamLen;
return B256ToB64Bytes(encodedStreamLen); return B256ToB64Bytes(encodedStreamLen);
} }
int StreamNameIO::maxDecodedNameLen( int encodedStreamLen ) const int StreamNameIO::maxDecodedNameLen(int encodedStreamLen) const {
{
int decLen256 = B64ToB256Bytes(encodedStreamLen); int decLen256 = B64ToB256Bytes(encodedStreamLen);
return decLen256 - 2; return decLen256 - 2;
} }
int StreamNameIO::encodeName(const char *plaintextName, int length, int StreamNameIO::encodeName(const char *plaintextName, int length,
uint64_t *iv, char *encodedName ) const uint64_t *iv, char *encodedName) const {
{
uint64_t tmpIV = 0; uint64_t tmpIV = 0;
if( iv && _interface >= 2 ) if (iv && _interface >= 2) tmpIV = *iv;
tmpIV = *iv;
unsigned int mac = _cipher->MAC_16( (const unsigned char *)plaintextName, unsigned int mac =
length, _key, iv ); _cipher->MAC_16((const unsigned char *)plaintextName, length, _key, iv);
// add on checksum bytes // add on checksum bytes
unsigned char *encodeBegin; unsigned char *encodeBegin;
if(_interface >= 1) if (_interface >= 1) {
{
// current versions store the checksum at the beginning // current versions store the checksum at the beginning
encodedName[0] = (mac >> 8) & 0xff; encodedName[0] = (mac >> 8) & 0xff;
encodedName[1] = (mac) & 0xff; encodedName[1] = (mac) & 0xff;
encodeBegin = (unsigned char *)encodedName + 2; encodeBegin = (unsigned char *)encodedName + 2;
} else } else {
{
// encfs 0.x stored checksums at the end. // encfs 0.x stored checksums at the end.
encodedName[length] = (mac >> 8) & 0xff; encodedName[length] = (mac >> 8) & 0xff;
encodedName[length + 1] = (mac) & 0xff; encodedName[length + 1] = (mac) & 0xff;
@ -136,22 +118,19 @@ int StreamNameIO::encodeName( const char *plaintextName, int length,
int encodedStreamLen = length + 2; int encodedStreamLen = length + 2;
int encLen64 = B256ToB64Bytes(encodedStreamLen); int encLen64 = B256ToB64Bytes(encodedStreamLen);
changeBase2Inline( (unsigned char *)encodedName, encodedStreamLen, changeBase2Inline((unsigned char *)encodedName, encodedStreamLen, 8, 6, true);
8, 6, true );
B64ToAscii((unsigned char *)encodedName, encLen64); B64ToAscii((unsigned char *)encodedName, encLen64);
return encLen64; return encLen64;
} }
int StreamNameIO::decodeName( const char *encodedName, int length, int StreamNameIO::decodeName(const char *encodedName, int length, uint64_t *iv,
uint64_t *iv, char *plaintextName ) const char *plaintextName) const {
{
rAssert(length > 2); rAssert(length > 2);
int decLen256 = B64ToB256Bytes(length); int decLen256 = B64ToB256Bytes(length);
int decodedStreamLen = decLen256 - 2; int decodedStreamLen = decLen256 - 2;
if(decodedStreamLen <= 0) if (decodedStreamLen <= 0) throw ERROR("Filename too small to decode");
throw ERROR("Filename too small to decode");
BUFFER_INIT(tmpBuf, 32, (unsigned int)length); BUFFER_INIT(tmpBuf, 32, (unsigned int)length);
@ -163,22 +142,19 @@ int StreamNameIO::decodeName( const char *encodedName, int length,
// pull out the checksum value which is used as an initialization vector // pull out the checksum value which is used as an initialization vector
uint64_t tmpIV = 0; uint64_t tmpIV = 0;
unsigned int mac; unsigned int mac;
if(_interface >= 1) if (_interface >= 1) {
{
// current versions store the checksum at the beginning // current versions store the checksum at the beginning
mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8 mac = ((unsigned int)((unsigned char)tmpBuf[0])) << 8 |
| ((unsigned int)((unsigned char)tmpBuf[1])); ((unsigned int)((unsigned char)tmpBuf[1]));
// version 2 adds support for IV chaining.. // version 2 adds support for IV chaining..
if( iv && _interface >= 2 ) if (iv && _interface >= 2) tmpIV = *iv;
tmpIV = *iv;
memcpy(plaintextName, tmpBuf + 2, decodedStreamLen); memcpy(plaintextName, tmpBuf + 2, decodedStreamLen);
} else } else {
{
// encfs 0.x stored checksums at the end. // encfs 0.x stored checksums at the end.
mac = ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen])) << 8 mac = ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen])) << 8 |
| ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen+1])); ((unsigned int)((unsigned char)tmpBuf[decodedStreamLen + 1]));
memcpy(plaintextName, tmpBuf, decodedStreamLen); memcpy(plaintextName, tmpBuf, decodedStreamLen);
} }
@ -192,8 +168,7 @@ int StreamNameIO::decodeName( const char *encodedName, int length,
decodedStreamLen, _key, iv); decodedStreamLen, _key, iv);
BUFFER_RESET(tmpBuf); BUFFER_RESET(tmpBuf);
if(mac2 != mac) if (mac2 != mac) {
{
rDebug("checksum mismatch: expected %u, got %u", mac, mac2); rDebug("checksum mismatch: expected %u, got %u", mac, mac2);
rDebug("on decode of %i bytes", decodedStreamLen); rDebug("on decode of %i bytes", decodedStreamLen);
throw ERROR("checksum mismatch in filename decode"); throw ERROR("checksum mismatch in filename decode");
@ -202,8 +177,4 @@ int StreamNameIO::decodeName( const char *encodedName, int length,
return decodedStreamLen; return decodedStreamLen;
} }
bool StreamNameIO::Enabled() bool StreamNameIO::Enabled() { return true; }
{
return true;
}

View File

@ -26,13 +26,11 @@
class Cipher; class Cipher;
class StreamNameIO : public NameIO class StreamNameIO : public NameIO {
{
public: public:
static rel::Interface CurrentInterface(); static rel::Interface CurrentInterface();
StreamNameIO( const rel::Interface &iface, StreamNameIO(const rel::Interface &iface, const shared_ptr<Cipher> &cipher,
const shared_ptr<Cipher> &cipher,
const CipherKey &key); const CipherKey &key);
virtual ~StreamNameIO(); virtual ~StreamNameIO();
@ -43,17 +41,17 @@ public:
// hack to help with static builds // hack to help with static builds
static bool Enabled(); static bool Enabled();
protected: protected:
virtual int encodeName( const char *plaintextName, int length, virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
uint64_t *iv, char *encodedName ) const; char *encodedName) const;
virtual int decodeName( const char *encodedName, int length, virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
uint64_t *iv, char *plaintextName ) const; char *plaintextName) const;
private: private:
int _interface; int _interface;
shared_ptr<Cipher> _cipher; shared_ptr<Cipher> _cipher;
CipherKey _key; CipherKey _key;
}; };
#endif #endif

View File

@ -27,8 +27,7 @@
// 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
// enough. // enough.
void changeBase2(unsigned char *src, int srcLen, int src2Pow, void changeBase2(unsigned char *src, int srcLen, int src2Pow,
unsigned char *dst, int dstLen, int dst2Pow) unsigned char *dst, int dstLen, int dst2Pow) {
{
unsigned long work = 0; unsigned long work = 0;
int workBits = 0; // number of bits left in the work buffer int workBits = 0; // number of bits left in the work buffer
unsigned char *end = src + srcLen; unsigned char *end = src + srcLen;
@ -37,13 +36,11 @@ void changeBase2(unsigned char *src, int srcLen, int src2Pow,
// copy the new bits onto the high bits of the stream. // copy the new bits onto the high bits of the stream.
// The bits that fall off the low end are the output bits. // The bits that fall off the low end are the output bits.
while(src != end) while (src != end) {
{
work |= ((unsigned long)(*src++)) << workBits; work |= ((unsigned long)(*src++)) << workBits;
workBits += src2Pow; workBits += src2Pow;
while(workBits >= dst2Pow) while (workBits >= dst2Pow) {
{
*dst++ = work & mask; *dst++ = work & mask;
work >>= dst2Pow; work >>= dst2Pow;
workBits -= dst2Pow; workBits -= dst2Pow;
@ -51,8 +48,7 @@ void changeBase2(unsigned char *src, int srcLen, int src2Pow,
} }
// now, we could have a partial value left in the work buffer.. // now, we could have a partial value left in the work buffer..
if(workBits && ((dst - origDst) < dstLen)) if (workBits && ((dst - origDst) < dstLen)) *dst++ = work & mask;
*dst++ = work & mask;
} }
/* /*
@ -62,22 +58,16 @@ void changeBase2(unsigned char *src, int srcLen, int src2Pow,
Uses the stack to store output values. Recurse every time a new value is Uses the stack to store output values. Recurse every time a new value is
to be written, then write the value at the tail end of the recursion. to be written, then write the value at the tail end of the recursion.
*/ */
static static void changeBase2Inline(unsigned char *src, int srcLen, int src2Pow,
void changeBase2Inline(unsigned char *src, int srcLen, int dst2Pow, bool outputPartialLastByte,
int src2Pow, int dst2Pow, unsigned long work, int workBits,
bool outputPartialLastByte, unsigned char *outLoc) {
unsigned long work,
int workBits,
unsigned char *outLoc)
{
const int mask = (1 << dst2Pow) - 1; const int mask = (1 << dst2Pow) - 1;
if(!outLoc) if (!outLoc) outLoc = src;
outLoc = src;
// copy the new bits onto the high bits of the stream. // copy the new bits onto the high bits of the stream.
// The bits that fall off the low end are the output bits. // The bits that fall off the low end are the output bits.
while(srcLen && workBits < dst2Pow) while (srcLen && workBits < dst2Pow) {
{
work |= ((unsigned long)(*src++)) << workBits; work |= ((unsigned long)(*src++)) << workBits;
workBits += src2Pow; workBits += src2Pow;
--srcLen; --srcLen;
@ -88,22 +78,18 @@ void changeBase2Inline(unsigned char *src, int srcLen,
work >>= dst2Pow; work >>= dst2Pow;
workBits -= dst2Pow; workBits -= dst2Pow;
if(srcLen) if (srcLen) {
{
// more input left, so recurse // more input left, so recurse
changeBase2Inline( src, srcLen, src2Pow, dst2Pow, changeBase2Inline(src, srcLen, src2Pow, dst2Pow, outputPartialLastByte,
outputPartialLastByte, work, workBits, outLoc+1); work, workBits, outLoc + 1);
*outLoc = outVal; *outLoc = outVal;
} else } else {
{
// no input left, we can write remaining values directly // no input left, we can write remaining values directly
*outLoc++ = outVal; *outLoc++ = outVal;
// we could have a partial value left in the work buffer.. // we could have a partial value left in the work buffer..
if(outputPartialLastByte) if (outputPartialLastByte) {
{ while (workBits > 0) {
while(workBits > 0)
{
*outLoc++ = work & mask; *outLoc++ = work & mask;
work >>= dst2Pow; work >>= dst2Pow;
workBits -= dst2Pow; workBits -= dst2Pow;
@ -112,15 +98,12 @@ void changeBase2Inline(unsigned char *src, int srcLen,
} }
} }
void changeBase2Inline(unsigned char *src, int srcLen, void changeBase2Inline(unsigned char *src, int srcLen, int src2Pow, int dst2Pow,
int src2Pow, int dst2Pow, bool outputPartialLastByte) {
bool outputPartialLastByte) changeBase2Inline(src, srcLen, src2Pow, dst2Pow, outputPartialLastByte, 0, 0,
{ 0);
changeBase2Inline(src, srcLen, src2Pow, dst2Pow,
outputPartialLastByte, 0, 0, 0);
} }
// character set for ascii b64: // character set for ascii b64:
// ",-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" // ",-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
// a standard base64 (eg a64l doesn't use ',-' but uses './'. We don't // a standard base64 (eg a64l doesn't use ',-' but uses './'. We don't
@ -128,13 +111,10 @@ void changeBase2Inline(unsigned char *src, int srcLen,
// '.' included in the encrypted names, so that it can be reserved for files // '.' included in the encrypted names, so that it can be reserved for files
// with special meaning. // with special meaning.
static const char B642AsciiTable[] = ",-0123456789"; static const char B642AsciiTable[] = ",-0123456789";
void B64ToAscii(unsigned char *in, int length) void B64ToAscii(unsigned char *in, int length) {
{ for (int offset = 0; offset < length; ++offset) {
for(int offset=0; offset<length; ++offset)
{
int ch = in[offset]; int ch = in[offset];
if(ch > 11) if (ch > 11) {
{
if (ch > 37) if (ch > 37)
ch += 'a' - 38; ch += 'a' - 38;
else else
@ -150,18 +130,14 @@ static const unsigned char Ascii2B64Table[] =
" 01 23456789:; "; " 01 23456789:; ";
// 0123456789 123456789 123456789 123456789 123456789 123456789 1234 // 0123456789 123456789 123456789 123456789 123456789 123456789 1234
// 0 1 2 3 4 5 6 // 0 1 2 3 4 5 6
void AsciiToB64(unsigned char *in, int length) void AsciiToB64(unsigned char *in, int length) {
{
return AsciiToB64(in, in, length); return AsciiToB64(in, in, length);
} }
void AsciiToB64(unsigned char *out, const unsigned char *in, int length) void AsciiToB64(unsigned char *out, const unsigned char *in, int length) {
{ while (length--) {
while(length--)
{
unsigned char ch = *in++; unsigned char ch = *in++;
if(ch >= 'A') if (ch >= 'A') {
{
if (ch >= 'a') if (ch >= 'a')
ch += 38 - 'a'; ch += 38 - 'a';
else else
@ -173,11 +149,8 @@ void AsciiToB64(unsigned char *out, const unsigned char *in, int length)
} }
} }
void B32ToAscii(unsigned char *buf, int len) {
void B32ToAscii(unsigned char *buf, int len) for (int offset = 0; offset < len; ++offset) {
{
for(int offset=0; offset<len; ++offset)
{
int ch = buf[offset]; int ch = buf[offset];
if (ch >= 0 && ch < 26) if (ch >= 0 && ch < 26)
ch += 'A'; ch += 'A';
@ -188,15 +161,12 @@ void B32ToAscii(unsigned char *buf, int len)
} }
} }
void AsciiToB32(unsigned char *in, int length) void AsciiToB32(unsigned char *in, int length) {
{
return AsciiToB32(in, in, length); return AsciiToB32(in, in, length);
} }
void AsciiToB32(unsigned char *out, const unsigned char *in, int length) void AsciiToB32(unsigned char *out, const unsigned char *in, int length) {
{ while (length--) {
while(length--)
{
unsigned char ch = *in++; unsigned char ch = *in++;
int lch = toupper(ch); int lch = toupper(ch);
if (lch >= 'A') if (lch >= 'A')
@ -207,4 +177,3 @@ void AsciiToB32(unsigned char *out, const unsigned char *in, int length)
*out++ = (unsigned char)lch; *out++ = (unsigned char)lch;
} }
} }

View File

@ -21,28 +21,22 @@
#ifndef _base64_incl_ #ifndef _base64_incl_
#define _base64_incl_ #define _base64_incl_
inline int B64ToB256Bytes(int numB64Bytes) {
inline int B64ToB256Bytes( int numB64Bytes )
{
return (numB64Bytes * 6) / 8; // round down return (numB64Bytes * 6) / 8; // round down
} }
inline int B32ToB256Bytes( int numB32Bytes ) inline int B32ToB256Bytes(int numB32Bytes) {
{
return (numB32Bytes * 5) / 8; // round down return (numB32Bytes * 5) / 8; // round down
} }
inline int B256ToB64Bytes( int numB256Bytes ) inline int B256ToB64Bytes(int numB256Bytes) {
{
return (numB256Bytes * 8 + 5) / 6; // round up return (numB256Bytes * 8 + 5) / 6; // round up
} }
inline int B256ToB32Bytes( int numB256Bytes ) inline int B256ToB32Bytes(int numB256Bytes) {
{
return (numB256Bytes * 8 + 4) / 5; // round up return (numB256Bytes * 8 + 4) / 5; // round up
} }
/* /*
convert data between different bases - each being a power of 2. convert data between different bases - each being a power of 2.
*/ */
@ -52,10 +46,8 @@ void changeBase2(unsigned char *src, int srcLength, int srcPow2,
/* /*
same as changeBase2, but writes output over the top of input data. same as changeBase2, but writes output over the top of input data.
*/ */
void changeBase2Inline(unsigned char *buf, int srcLength, void changeBase2Inline(unsigned char *buf, int srcLength, int srcPow2,
int srcPow2, int dst2Pow, int dst2Pow, bool outputPartialLastByte);
bool outputPartialLastByte);
// inplace translation from values [0,2^6] => base64 ASCII // inplace translation from values [0,2^6] => base64 ASCII
void B64ToAscii(unsigned char *buf, int length); void B64ToAscii(unsigned char *buf, int length);
@ -71,4 +63,3 @@ 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);
#endif #endif

View File

@ -4,7 +4,6 @@
// This header stores workaround code for dealing with incompatible changes // This header stores workaround code for dealing with incompatible changes
// made to boost archive/serialization classes. // made to boost archive/serialization classes.
#if (BOOST_VERSION <= 104100) #if (BOOST_VERSION <= 104100)
// Easy case, boost archive serial numbers are sizeof(int) // Easy case, boost archive serial numbers are sizeof(int)
BOOST_CLASS_VERSION(EncFSConfig, V6SubVersion) BOOST_CLASS_VERSION(EncFSConfig, V6SubVersion)
@ -23,45 +22,39 @@ BOOST_CLASS_VERSION(EncFSConfig, V6SubVersion)
BOOST_CLASS_VERSION(EncFSConfig, 20) BOOST_CLASS_VERSION(EncFSConfig, 20)
namespace boost { namespace boost {
namespace archive { namespace archive {
namespace detail { namespace detail {
// Specialize iserializer class in order to get rid of version check // Specialize iserializer class in order to get rid of version check
template <class Archive> template <class Archive>
class iserializer<Archive, EncFSConfig> : public basic_iserializer class iserializer<Archive, EncFSConfig> : public basic_iserializer {
{
private: private:
virtual void destroy(/*const*/ void *address) const { virtual void destroy(/*const*/ void *address) const {
boost::serialization::access::destroy(static_cast<EncFSConfig *>(address)); boost::serialization::access::destroy(static_cast<EncFSConfig *>(address));
} }
protected: protected:
explicit iserializer() : explicit iserializer()
basic_iserializer( : basic_iserializer(boost::serialization::singleton<
boost::serialization::singleton< BOOST_DEDUCED_TYPENAME boost::serialization::
BOOST_DEDUCED_TYPENAME type_info_implementation<
boost::serialization::type_info_implementation<EncFSConfig>::type EncFSConfig>::type>::get_const_instance()) {}
>::get_const_instance()
)
{}
public: public:
virtual BOOST_DLLEXPORT void load_object_data( virtual BOOST_DLLEXPORT void load_object_data(
basic_iarchive & ar, basic_iarchive &ar, void *x,
void *x, const unsigned int file_version) const BOOST_USED;
const unsigned int file_version
) const BOOST_USED;
virtual bool class_info() const { virtual bool class_info() const {
return boost::serialization::implementation_level<EncFSConfig>::value return boost::serialization::implementation_level<EncFSConfig>::value >=
>= boost::serialization::object_class_info; boost::serialization::object_class_info;
} }
virtual bool tracking(const unsigned int /* flags */) const { virtual bool tracking(const unsigned int /* flags */) const {
return boost::serialization::tracking_level<EncFSConfig>::value return boost::serialization::tracking_level<EncFSConfig>::value ==
== boost::serialization::track_always boost::serialization::track_always ||
|| ( boost::serialization::tracking_level<EncFSConfig>::value (boost::serialization::tracking_level<EncFSConfig>::value ==
== boost::serialization::track_selectively boost::serialization::track_selectively &&
&& serialized_as_pointer()); serialized_as_pointer());
} }
virtual version_type version() const { virtual version_type version() const {
return version_type(::boost::serialization::version<EncFSConfig>::value); return version_type(::boost::serialization::version<EncFSConfig>::value);
@ -74,23 +67,15 @@ public:
template <class Archive> template <class Archive>
BOOST_DLLEXPORT void iserializer<Archive, EncFSConfig>::load_object_data( BOOST_DLLEXPORT void iserializer<Archive, EncFSConfig>::load_object_data(
basic_iarchive & ar, basic_iarchive &ar, void *x, const unsigned int file_version) const {
void *x,
const unsigned int file_version
) const {
boost::serialization::serialize_adl( boost::serialization::serialize_adl(
boost::serialization::smart_cast_reference<Archive &>(ar), boost::serialization::smart_cast_reference<Archive &>(ar),
* static_cast<EncFSConfig *>(x), *static_cast<EncFSConfig *>(x), file_version);
file_version
);
} }
} }
} }
} }
#endif #endif
#endif // BOOST_VERSIONING_INCL #endif // BOOST_VERSIONING_INCL

View File

@ -37,7 +37,6 @@
#include <sys/xattr.h> #include <sys/xattr.h>
#endif #endif
#include <string> #include <string>
#include <map> #include <map>
@ -68,40 +67,36 @@ using namespace boost;
static RLogChannel *Info = DEF_CHANNEL("info", Log_Info); static RLogChannel *Info = DEF_CHANNEL("info", Log_Info);
static EncFS_Context * context() static EncFS_Context *context() {
{
return (EncFS_Context *)fuse_get_context()->private_data; return (EncFS_Context *)fuse_get_context()->private_data;
} }
// helper function -- apply a functor to a cipher path, given the plain path // helper function -- apply a functor to a cipher path, given the plain path
template <typename T> template <typename T>
static int withCipherPath(const char *opName, const char *path, static int withCipherPath(const char *opName, const char *path,
int (*op)(EncFS_Context *, const string &name, T data ), T data, int (*op)(EncFS_Context *, const string &name,
bool passReturnCode = false ) T data),
{ T data, bool passReturnCode = false) {
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
int res = -EIO; int res = -EIO;
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(!FSRoot) if (!FSRoot) return res;
return res;
try try {
{
string cyName = FSRoot->cipherPath(path); string cyName = FSRoot->cipherPath(path);
rLog(Info, "%s %s", opName, cyName.c_str()); rLog(Info, "%s %s", opName, cyName.c_str());
res = op(ctx, cyName, data); res = op(ctx, cyName, data);
if(res == -1) if (res == -1) {
{
int eno = errno; int eno = errno;
rInfo("%s error: %s", opName, strerror(eno)); rInfo("%s error: %s", opName, strerror(eno));
res = -eno; res = -eno;
} else if (!passReturnCode) } else if (!passReturnCode)
res = ESUCCESS; res = ESUCCESS;
} catch( rlog::Error &err ) }
{ catch (rlog::Error &err) {
rError("error caught in %s", opName); rError("error caught in %s", opName);
err.log(_RLWarningChannel); err.log(_RLWarningChannel);
} }
@ -110,19 +105,16 @@ static int withCipherPath( const char *opName, const char *path,
// helper function -- apply a functor to a node // helper function -- apply a functor to a node
template <typename T> template <typename T>
static int withFileNode( const char *opName, static int withFileNode(const char *opName, const char *path,
const char *path, struct fuse_file_info *fi, struct fuse_file_info *fi,
int (*op)(FileNode *, T data ), T data ) int (*op)(FileNode *, T data), T data) {
{
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
int res = -EIO; int res = -EIO;
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(!FSRoot) if (!FSRoot) return res;
return res;
try try {
{
shared_ptr<FileNode> fnode; shared_ptr<FileNode> fnode;
if (fi != NULL) if (fi != NULL)
@ -134,10 +126,9 @@ static int withFileNode( const char *opName,
rLog(Info, "%s %s", opName, fnode->cipherName()); rLog(Info, "%s %s", opName, fnode->cipherName());
res = op(fnode.get(), data); res = op(fnode.get(), data);
if(res < 0) if (res < 0) rInfo("%s error: %s", opName, strerror(-res));
rInfo("%s error: %s", opName, strerror(-res)); }
} catch( rlog::Error &err ) catch (rlog::Error &err) {
{
rError("error caught in %s", opName); rError("error caught in %s", opName);
err.log(_RLWarningChannel); err.log(_RLWarningChannel);
} }
@ -155,21 +146,17 @@ static int withFileNode( const char *opName,
can be done here. can be done here.
*/ */
int _do_getattr(FileNode *fnode, struct stat *stbuf) int _do_getattr(FileNode *fnode, struct stat *stbuf) {
{
int res = fnode->getAttr(stbuf); int res = fnode->getAttr(stbuf);
if(res == ESUCCESS && S_ISLNK(stbuf->st_mode)) if (res == ESUCCESS && S_ISLNK(stbuf->st_mode)) {
{
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(FSRoot) if (FSRoot) {
{
// determine plaintext link size.. Easiest to read and decrypt.. // determine plaintext link size.. Easiest to read and decrypt..
scoped_array<char> buf(new char[stbuf->st_size + 1]); scoped_array<char> buf(new char[stbuf->st_size + 1]);
res = ::readlink(fnode->cipherName(), buf.get(), stbuf->st_size); res = ::readlink(fnode->cipherName(), buf.get(), stbuf->st_size);
if(res >= 0) if (res >= 0) {
{
// other functions expect c-strings to be null-terminated, which // other functions expect c-strings to be null-terminated, which
// readlink doesn't provide // readlink doesn't provide
buf[res] = '\0'; buf[res] = '\0';
@ -185,234 +172,198 @@ int _do_getattr(FileNode *fnode, struct stat *stbuf)
return res; return res;
} }
int encfs_getattr(const char *path, struct stat *stbuf) int encfs_getattr(const char *path, struct stat *stbuf) {
{
return withFileNode("getattr", path, NULL, _do_getattr, stbuf); return withFileNode("getattr", path, NULL, _do_getattr, stbuf);
} }
int encfs_fgetattr(const char *path, struct stat *stbuf, int encfs_fgetattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi) struct fuse_file_info *fi) {
{
return withFileNode("fgetattr", path, fi, _do_getattr, stbuf); return withFileNode("fgetattr", path, fi, _do_getattr, stbuf);
} }
int encfs_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler) int encfs_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler) {
{
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
int res = ESUCCESS; int res = ESUCCESS;
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(!FSRoot) if (!FSRoot) return res;
return res;
try try {
{
DirTraverse dt = FSRoot->openDir(path); DirTraverse dt = FSRoot->openDir(path);
rLog(Info, "getdir on %s", FSRoot->cipherPath(path).c_str()); rLog(Info, "getdir on %s", FSRoot->cipherPath(path).c_str());
if(dt.valid()) if (dt.valid()) {
{
int fileType = 0; int fileType = 0;
ino_t inode = 0; ino_t inode = 0;
std::string name = dt.nextPlaintextName(&fileType, &inode); std::string name = dt.nextPlaintextName(&fileType, &inode);
while( !name.empty() ) while (!name.empty()) {
{
res = filler(h, name.c_str(), fileType, inode); res = filler(h, name.c_str(), fileType, inode);
if(res != ESUCCESS) if (res != ESUCCESS) break;
break;
name = dt.nextPlaintextName(&fileType, &inode); name = dt.nextPlaintextName(&fileType, &inode);
} }
} else } else {
{
rInfo("getdir request invalid, path: '%s'", path); rInfo("getdir request invalid, path: '%s'", path);
} }
return res; return res;
} catch( rlog::Error &err ) }
{ catch (rlog::Error &err) {
rError("Error caught in getdir"); rError("Error caught in getdir");
err.log(_RLWarningChannel); err.log(_RLWarningChannel);
return -EIO; return -EIO;
} }
} }
int encfs_mknod(const char *path, mode_t mode, dev_t rdev) int encfs_mknod(const char *path, mode_t mode, dev_t rdev) {
{
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
int res = -EIO; int res = -EIO;
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(!FSRoot) if (!FSRoot) return res;
return res;
try try {
{
shared_ptr<FileNode> fnode = FSRoot->lookupNode(path, "mknod"); shared_ptr<FileNode> fnode = FSRoot->lookupNode(path, "mknod");
rLog(Info, "mknod on %s, mode %i, dev %" PRIi64, rLog(Info, "mknod on %s, mode %i, dev %" PRIi64, fnode->cipherName(), mode,
fnode->cipherName(), mode, (int64_t)rdev); (int64_t)rdev);
uid_t uid = 0; uid_t uid = 0;
gid_t gid = 0; gid_t gid = 0;
if(ctx->publicFilesystem) if (ctx->publicFilesystem) {
{
fuse_context *context = fuse_get_context(); fuse_context *context = fuse_get_context();
uid = context->uid; uid = context->uid;
gid = context->gid; gid = context->gid;
} }
res = fnode->mknod(mode, rdev, uid, gid); res = fnode->mknod(mode, rdev, uid, gid);
// Is this error due to access problems? // Is this error due to access problems?
if(ctx->publicFilesystem && -res == EACCES) if (ctx->publicFilesystem && -res == EACCES) {
{
// try again using the parent dir's group // try again using the parent dir's group
string parent = fnode->plaintextParent(); string parent = fnode->plaintextParent();
rInfo("trying public filesystem workaround for %s", parent.c_str()); rInfo("trying public filesystem workaround for %s", parent.c_str());
shared_ptr<FileNode> dnode = shared_ptr<FileNode> dnode = FSRoot->lookupNode(parent.c_str(), "mknod");
FSRoot->lookupNode( parent.c_str(), "mknod" );
struct stat st; struct stat st;
if (dnode->getAttr(&st) == 0) if (dnode->getAttr(&st) == 0)
res = fnode->mknod(mode, rdev, uid, st.st_gid); res = fnode->mknod(mode, rdev, uid, st.st_gid);
} }
} catch( rlog::Error &err ) }
{ catch (rlog::Error &err) {
rError("error caught in mknod"); rError("error caught in mknod");
err.log(_RLWarningChannel); err.log(_RLWarningChannel);
} }
return res; return res;
} }
int encfs_mkdir(const char *path, mode_t mode) int encfs_mkdir(const char *path, mode_t mode) {
{
fuse_context *fctx = fuse_get_context(); fuse_context *fctx = fuse_get_context();
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
int res = -EIO; int res = -EIO;
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(!FSRoot) if (!FSRoot) return res;
return res;
try try {
{
uid_t uid = 0; uid_t uid = 0;
gid_t gid = 0; gid_t gid = 0;
if(ctx->publicFilesystem) if (ctx->publicFilesystem) {
{
uid = fctx->uid; uid = fctx->uid;
gid = fctx->gid; gid = fctx->gid;
} }
res = FSRoot->mkdir(path, mode, uid, gid); res = FSRoot->mkdir(path, mode, uid, gid);
// Is this error due to access problems? // Is this error due to access problems?
if(ctx->publicFilesystem && -res == EACCES) if (ctx->publicFilesystem && -res == EACCES) {
{
// try again using the parent dir's group // try again using the parent dir's group
string parent = parentDirectory(path); string parent = parentDirectory(path);
shared_ptr<FileNode> dnode = shared_ptr<FileNode> dnode = FSRoot->lookupNode(parent.c_str(), "mkdir");
FSRoot->lookupNode( parent.c_str(), "mkdir" );
struct stat st; struct stat st;
if (dnode->getAttr(&st) == 0) if (dnode->getAttr(&st) == 0)
res = FSRoot->mkdir(path, mode, uid, st.st_gid); res = FSRoot->mkdir(path, mode, uid, st.st_gid);
} }
} catch( rlog::Error &err ) }
{ catch (rlog::Error &err) {
rError("error caught in mkdir"); rError("error caught in mkdir");
err.log(_RLWarningChannel); err.log(_RLWarningChannel);
} }
return res; return res;
} }
int encfs_unlink(const char *path) int encfs_unlink(const char *path) {
{
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
int res = -EIO; int res = -EIO;
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(!FSRoot) if (!FSRoot) return res;
return res;
try try {
{
// let DirNode handle it atomically so that it can handle race // let DirNode handle it atomically so that it can handle race
// conditions // conditions
res = FSRoot->unlink(path); res = FSRoot->unlink(path);
} catch( rlog::Error &err ) }
{ catch (rlog::Error &err) {
rError("error caught in unlink"); rError("error caught in unlink");
err.log(_RLWarningChannel); err.log(_RLWarningChannel);
} }
return res; return res;
} }
int _do_rmdir(EncFS_Context *, const string &cipherPath, int) {
int _do_rmdir(EncFS_Context *, const string &cipherPath, int )
{
return rmdir(cipherPath.c_str()); return rmdir(cipherPath.c_str());
} }
int encfs_rmdir(const char *path) int encfs_rmdir(const char *path) {
{
return withCipherPath("rmdir", path, _do_rmdir, 0); return withCipherPath("rmdir", path, _do_rmdir, 0);
} }
int _do_readlink(EncFS_Context *ctx, const string &cyName, int _do_readlink(EncFS_Context *ctx, const string &cyName,
tuple<char *, size_t> data ) tuple<char *, size_t> data) {
{
char *buf = data.get<0>(); char *buf = data.get<0>();
size_t size = data.get<1>(); size_t size = data.get<1>();
int res = ESUCCESS; int res = ESUCCESS;
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(!FSRoot) if (!FSRoot) return res;
return res;
res = ::readlink(cyName.c_str(), buf, size - 1); res = ::readlink(cyName.c_str(), buf, size - 1);
if(res == -1) if (res == -1) return -errno;
return -errno;
buf[res] = '\0'; // ensure null termination buf[res] = '\0'; // ensure null termination
string decodedName; string decodedName;
try try {
{
decodedName = FSRoot->plainPath(buf); decodedName = FSRoot->plainPath(buf);
} catch(...) { } }
catch (...) {
}
if(!decodedName.empty()) if (!decodedName.empty()) {
{
strncpy(buf, decodedName.c_str(), size - 1); strncpy(buf, decodedName.c_str(), size - 1);
buf[size - 1] = '\0'; buf[size - 1] = '\0';
return ESUCCESS; return ESUCCESS;
} else } else {
{
rWarning("Error decoding link"); rWarning("Error decoding link");
return -1; return -1;
} }
} }
int encfs_readlink(const char *path, char *buf, size_t size) int encfs_readlink(const char *path, char *buf, size_t size) {
{ return withCipherPath("readlink", path, _do_readlink, make_tuple(buf, size));
return withCipherPath( "readlink", path, _do_readlink,
make_tuple(buf, size) );
} }
int encfs_symlink(const char *from, const char *to) int encfs_symlink(const char *from, const char *to) {
{
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
int res = -EIO; int res = -EIO;
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(!FSRoot) if (!FSRoot) return res;
return res;
try try {
{
// allow fully qualified names in symbolic links. // allow fully qualified names in symbolic links.
string fromCName = FSRoot->relativeCipherPath(from); string fromCName = FSRoot->relativeCipherPath(from);
string toCName = FSRoot->cipherPath(to); string toCName = FSRoot->cipherPath(to);
@ -423,121 +374,99 @@ int encfs_symlink(const char *from, const char *to)
// uid/gid provided by the fuse_context. // uid/gid provided by the fuse_context.
int olduid = -1; int olduid = -1;
int oldgid = -1; int oldgid = -1;
if(ctx->publicFilesystem) if (ctx->publicFilesystem) {
{
fuse_context *context = fuse_get_context(); fuse_context *context = fuse_get_context();
olduid = setfsuid(context->uid); olduid = setfsuid(context->uid);
oldgid = setfsgid(context->gid); oldgid = setfsgid(context->gid);
} }
res = ::symlink(fromCName.c_str(), toCName.c_str()); res = ::symlink(fromCName.c_str(), toCName.c_str());
if(olduid >= 0) if (olduid >= 0) setfsuid(olduid);
setfsuid( olduid ); if (oldgid >= 0) setfsgid(oldgid);
if(oldgid >= 0)
setfsgid( oldgid );
if (res == -1) if (res == -1)
res = -errno; res = -errno;
else else
res = ESUCCESS; res = ESUCCESS;
} catch( rlog::Error &err ) }
{ catch (rlog::Error &err) {
rError("error caught in symlink"); rError("error caught in symlink");
err.log(_RLWarningChannel); err.log(_RLWarningChannel);
} }
return res; return res;
} }
int encfs_link(const char *from, const char *to) int encfs_link(const char *from, const char *to) {
{
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
int res = -EIO; int res = -EIO;
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(!FSRoot) if (!FSRoot) return res;
return res;
try try {
{
res = FSRoot->link(from, to); res = FSRoot->link(from, to);
} catch( rlog::Error &err ) }
{ catch (rlog::Error &err) {
rError("error caught in link"); rError("error caught in link");
err.log(_RLWarningChannel); err.log(_RLWarningChannel);
} }
return res; return res;
} }
int encfs_rename(const char *from, const char *to) int encfs_rename(const char *from, const char *to) {
{
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
int res = -EIO; int res = -EIO;
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(!FSRoot) if (!FSRoot) return res;
return res;
try try {
{
res = FSRoot->rename(from, to); res = FSRoot->rename(from, to);
} catch( rlog::Error &err ) }
{ catch (rlog::Error &err) {
rError("error caught in rename"); rError("error caught in rename");
err.log(_RLWarningChannel); err.log(_RLWarningChannel);
} }
return res; return res;
} }
int _do_chmod(EncFS_Context *, const string &cipherPath, mode_t mode) int _do_chmod(EncFS_Context *, const string &cipherPath, mode_t mode) {
{
return chmod(cipherPath.c_str(), mode); return chmod(cipherPath.c_str(), mode);
} }
int encfs_chmod(const char *path, mode_t mode) int encfs_chmod(const char *path, mode_t mode) {
{
return withCipherPath("chmod", path, _do_chmod, mode); return withCipherPath("chmod", path, _do_chmod, mode);
} }
int _do_chown(EncFS_Context *, const string &cyName, int _do_chown(EncFS_Context *, const string &cyName, tuple<uid_t, gid_t> data) {
tuple<uid_t, gid_t> data)
{
int res = lchown(cyName.c_str(), data.get<0>(), data.get<1>()); int res = lchown(cyName.c_str(), data.get<0>(), data.get<1>());
return (res == -1) ? -errno : ESUCCESS; return (res == -1) ? -errno : ESUCCESS;
} }
int encfs_chown(const char *path, uid_t uid, gid_t gid) int encfs_chown(const char *path, uid_t uid, gid_t gid) {
{
return withCipherPath("chown", path, _do_chown, make_tuple(uid, gid)); return withCipherPath("chown", path, _do_chown, make_tuple(uid, gid));
} }
int _do_truncate( FileNode *fnode, off_t size ) int _do_truncate(FileNode *fnode, off_t size) { return fnode->truncate(size); }
{
return fnode->truncate( size );
}
int encfs_truncate(const char *path, off_t size) int encfs_truncate(const char *path, off_t size) {
{
return withFileNode("truncate", path, NULL, _do_truncate, size); return withFileNode("truncate", path, NULL, _do_truncate, size);
} }
int encfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi) int encfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi) {
{
return withFileNode("ftruncate", path, fi, _do_truncate, size); return withFileNode("ftruncate", path, fi, _do_truncate, size);
} }
int _do_utime(EncFS_Context *, const string &cyName, struct utimbuf *buf) int _do_utime(EncFS_Context *, const string &cyName, struct utimbuf *buf) {
{
int res = utime(cyName.c_str(), buf); int res = utime(cyName.c_str(), buf);
return (res == -1) ? -errno : ESUCCESS; return (res == -1) ? -errno : ESUCCESS;
} }
int encfs_utime(const char *path, struct utimbuf *buf) int encfs_utime(const char *path, struct utimbuf *buf) {
{
return withCipherPath("utime", path, _do_utime, buf); return withCipherPath("utime", path, _do_utime, buf);
} }
int _do_utimens(EncFS_Context *, const string &cyName, int _do_utimens(EncFS_Context *, const string &cyName,
const struct timespec ts[2]) const struct timespec ts[2]) {
{
struct timeval tv[2]; struct timeval tv[2];
tv[0].tv_sec = ts[0].tv_sec; tv[0].tv_sec = ts[0].tv_sec;
tv[0].tv_usec = ts[0].tv_nsec / 1000; tv[0].tv_usec = ts[0].tv_nsec / 1000;
@ -548,38 +477,32 @@ int _do_utimens(EncFS_Context *, const string &cyName,
return (res == -1) ? -errno : ESUCCESS; return (res == -1) ? -errno : ESUCCESS;
} }
int encfs_utimens(const char *path, const struct timespec ts[2] ) int encfs_utimens(const char *path, const struct timespec ts[2]) {
{
return withCipherPath("utimens", path, _do_utimens, ts); return withCipherPath("utimens", path, _do_utimens, ts);
} }
int encfs_open(const char *path, struct fuse_file_info *file) int encfs_open(const char *path, struct fuse_file_info *file) {
{
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
int res = -EIO; int res = -EIO;
shared_ptr<DirNode> FSRoot = ctx->getRoot(&res); shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
if(!FSRoot) if (!FSRoot) return res;
return res;
try try {
{
shared_ptr<FileNode> fnode = shared_ptr<FileNode> fnode =
FSRoot->openNode(path, "open", file->flags, &res); FSRoot->openNode(path, "open", file->flags, &res);
if(fnode) if (fnode) {
{
rLog(Info, "encfs_open for %s, flags %i", fnode->cipherName(), rLog(Info, "encfs_open for %s, flags %i", fnode->cipherName(),
file->flags); file->flags);
if( res >= 0 ) if (res >= 0) {
{
file->fh = (uintptr_t)ctx->putNode(path, fnode); file->fh = (uintptr_t)ctx->putNode(path, fnode);
res = ESUCCESS; res = ESUCCESS;
} }
} }
} catch( rlog::Error &err ) }
{ catch (rlog::Error &err) {
rError("error caught in open"); rError("error caught in open");
err.log(_RLWarningChannel); err.log(_RLWarningChannel);
} }
@ -587,26 +510,22 @@ int encfs_open(const char *path, struct fuse_file_info *file)
return res; return res;
} }
int _do_flush(FileNode *fnode, int ) int _do_flush(FileNode *fnode, int) {
{
/* Flush can be called multiple times for an open file, so it doesn't /* Flush can be called multiple times for an open file, so it doesn't
close the file. However it is important to call close() for some close the file. However it is important to call close() for some
underlying filesystems (like NFS). underlying filesystems (like NFS).
*/ */
int res = fnode->open(O_RDONLY); int res = fnode->open(O_RDONLY);
if(res >= 0) if (res >= 0) {
{
int fh = res; int fh = res;
res = close(dup(fh)); res = close(dup(fh));
if(res == -1) if (res == -1) res = -errno;
res = -errno;
} }
return res; return res;
} }
int encfs_flush(const char *path, struct fuse_file_info *fi) int encfs_flush(const char *path, struct fuse_file_info *fi) {
{
return withFileNode("flush", path, fi, _do_flush, 0); return withFileNode("flush", path, fi, _do_flush, 0);
} }
@ -615,47 +534,39 @@ Note: This is advisory -- it might benefit us to keep file nodes around for a
bit after they are released just in case they are reopened soon. But that bit after they are released just in case they are reopened soon. But that
requires a cache layer. requires a cache layer.
*/ */
int encfs_release(const char *path, struct fuse_file_info *finfo) int encfs_release(const char *path, struct fuse_file_info *finfo) {
{
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
try try {
{
ctx->eraseNode(path, (void *)(uintptr_t)finfo->fh); ctx->eraseNode(path, (void *)(uintptr_t)finfo->fh);
return ESUCCESS; return ESUCCESS;
} catch( rlog::Error &err ) }
{ catch (rlog::Error &err) {
rError("error caught in release"); rError("error caught in release");
err.log(_RLWarningChannel); err.log(_RLWarningChannel);
return -EIO; return -EIO;
} }
} }
int _do_read(FileNode *fnode, tuple<unsigned char *, size_t, off_t> data) int _do_read(FileNode *fnode, tuple<unsigned char *, size_t, off_t> data) {
{
return fnode->read(data.get<2>(), data.get<0>(), data.get<1>()); return fnode->read(data.get<2>(), data.get<0>(), data.get<1>());
} }
int encfs_read(const char *path, char *buf, size_t size, off_t offset, int encfs_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *file) struct fuse_file_info *file) {
{
return withFileNode("read", path, file, _do_read, return withFileNode("read", path, file, _do_read,
make_tuple((unsigned char *)buf, size, offset)); make_tuple((unsigned char *)buf, size, offset));
} }
int _do_fsync(FileNode *fnode, int dataSync) int _do_fsync(FileNode *fnode, int dataSync) {
{
return fnode->sync(dataSync != 0); return fnode->sync(dataSync != 0);
} }
int encfs_fsync(const char *path, int dataSync, int encfs_fsync(const char *path, int dataSync, struct fuse_file_info *file) {
struct fuse_file_info *file)
{
return withFileNode("fsync", path, file, _do_fsync, dataSync); return withFileNode("fsync", path, file, _do_fsync, dataSync);
} }
int _do_write(FileNode *fnode, tuple<const char *, size_t, off_t> data) int _do_write(FileNode *fnode, tuple<const char *, size_t, off_t> data) {
{
size_t size = data.get<1>(); size_t size = data.get<1>();
if (fnode->write(data.get<2>(), (unsigned char *)data.get<0>(), size)) if (fnode->write(data.get<2>(), (unsigned char *)data.get<0>(), size))
return size; return size;
@ -663,36 +574,31 @@ int _do_write(FileNode *fnode, tuple<const char *, size_t, off_t> data)
return -EIO; return -EIO;
} }
int encfs_write(const char *path, const char *buf, size_t size, int encfs_write(const char *path, const char *buf, size_t size, off_t offset,
off_t offset, struct fuse_file_info *file) struct fuse_file_info *file) {
{
return withFileNode("write", path, file, _do_write, return withFileNode("write", path, file, _do_write,
make_tuple(buf, size, offset)); make_tuple(buf, size, offset));
} }
// statfs works even if encfs is detached.. // statfs works even if encfs is detached..
int encfs_statfs(const char *path, struct statvfs *st) int encfs_statfs(const char *path, struct statvfs *st) {
{
EncFS_Context *ctx = context(); EncFS_Context *ctx = context();
int res = -EIO; int res = -EIO;
try try {
{
(void)path; // path should always be '/' for now.. (void)path; // path should always be '/' for now..
rAssert(st != NULL); rAssert(st != NULL);
string cyName = ctx->rootCipherDir; string cyName = ctx->rootCipherDir;
rLog(Info, "doing statfs of %s", cyName.c_str()); rLog(Info, "doing statfs of %s", cyName.c_str());
res = statvfs(cyName.c_str(), st); res = statvfs(cyName.c_str(), st);
if(!res) if (!res) {
{
// adjust maximum name length.. // adjust maximum name length..
st->f_namemax = 6 * (st->f_namemax - 2) / 8; // approx.. st->f_namemax = 6 * (st->f_namemax - 2) / 8; // approx..
} }
if(res == -1) if (res == -1) res = -errno;
res = -errno; }
} catch( rlog::Error &err ) catch (rlog::Error &err) {
{
rError("error caught in statfs"); rError("error caught in statfs");
err.log(_RLWarningChannel); err.log(_RLWarningChannel);
} }
@ -701,89 +607,74 @@ int encfs_statfs(const char *path, struct statvfs *st)
#ifdef HAVE_XATTR #ifdef HAVE_XATTR
#ifdef XATTR_ADD_OPT #ifdef XATTR_ADD_OPT
int _do_setxattr(EncFS_Context *, const string &cyName, int _do_setxattr(EncFS_Context *, const string &cyName,
tuple<const char *, const char *, size_t, uint32_t> data) tuple<const char *, const char *, size_t, uint32_t> data) {
{
int options = 0; int options = 0;
return ::setxattr( cyName.c_str(), data.get<0>(), data.get<1>(), return ::setxattr(cyName.c_str(), data.get<0>(), data.get<1>(), data.get<2>(),
data.get<2>(), data.get<3>(), options ); data.get<3>(), options);
} }
int encfs_setxattr( const char *path, const char *name, int encfs_setxattr(const char *path, const char *name, const char *value,
const char *value, size_t size, int flags, uint32_t position ) size_t size, int flags, uint32_t position) {
{
(void)flags; (void)flags;
return withCipherPath("setxattr", path, _do_setxattr, return withCipherPath("setxattr", path, _do_setxattr,
make_tuple(name, value, size, position)); make_tuple(name, value, size, position));
} }
#else #else
int _do_setxattr(EncFS_Context *, const string &cyName, int _do_setxattr(EncFS_Context *, const string &cyName,
tuple<const char *, const char *, size_t, int> data) tuple<const char *, const char *, size_t, int> data) {
{ return ::setxattr(cyName.c_str(), data.get<0>(), data.get<1>(), data.get<2>(),
return ::setxattr( cyName.c_str(), data.get<0>(), data.get<1>(), data.get<3>());
data.get<2>(), data.get<3>() );
} }
int encfs_setxattr( const char *path, const char *name, int encfs_setxattr(const char *path, const char *name, const char *value,
const char *value, size_t size, int flags ) size_t size, int flags) {
{
return withCipherPath("setxattr", path, _do_setxattr, return withCipherPath("setxattr", path, _do_setxattr,
make_tuple(name, value, size, flags)); make_tuple(name, value, size, flags));
} }
#endif #endif
#ifdef XATTR_ADD_OPT #ifdef XATTR_ADD_OPT
int _do_getxattr(EncFS_Context *, const string &cyName, int _do_getxattr(EncFS_Context *, const string &cyName,
tuple<const char *, void *, size_t, uint32_t> data) tuple<const char *, void *, size_t, uint32_t> data) {
{
int options = 0; int options = 0;
return ::getxattr( cyName.c_str(), data.get<0>(), return ::getxattr(cyName.c_str(), data.get<0>(), data.get<1>(), data.get<2>(),
data.get<1>(), data.get<2>(), data.get<3>(), options ); data.get<3>(), options);
} }
int encfs_getxattr( const char *path, const char *name, int encfs_getxattr(const char *path, const char *name, char *value, size_t size,
char *value, size_t size, uint32_t position ) uint32_t position) {
{
return withCipherPath("getxattr", path, _do_getxattr, return withCipherPath("getxattr", path, _do_getxattr,
make_tuple(name, (void *)value, size, position), true); make_tuple(name, (void *)value, size, position), true);
} }
#else #else
int _do_getxattr(EncFS_Context *, const string &cyName, int _do_getxattr(EncFS_Context *, const string &cyName,
tuple<const char *, void *, size_t> data) tuple<const char *, void *, size_t> data) {
{ return ::getxattr(cyName.c_str(), data.get<0>(), data.get<1>(),
return ::getxattr( cyName.c_str(), data.get<0>(), data.get<2>());
data.get<1>(), data.get<2>());
} }
int encfs_getxattr( const char *path, const char *name, int encfs_getxattr(const char *path, const char *name, char *value,
char *value, size_t size ) size_t size) {
{
return withCipherPath("getxattr", path, _do_getxattr, return withCipherPath("getxattr", path, _do_getxattr,
make_tuple(name, (void *)value, size), true); make_tuple(name, (void *)value, size), true);
} }
#endif #endif
int _do_listxattr(EncFS_Context *, const string &cyName, int _do_listxattr(EncFS_Context *, const string &cyName,
tuple<char *, size_t> data) tuple<char *, size_t> data) {
{
#ifdef XATTR_ADD_OPT #ifdef XATTR_ADD_OPT
int options = 0; int options = 0;
int res = ::listxattr( cyName.c_str(), data.get<0>(), data.get<1>(), int res = ::listxattr(cyName.c_str(), data.get<0>(), data.get<1>(), options);
options );
#else #else
int res = ::listxattr(cyName.c_str(), data.get<0>(), data.get<1>()); int res = ::listxattr(cyName.c_str(), data.get<0>(), data.get<1>());
#endif #endif
return (res == -1) ? -errno : res; return (res == -1) ? -errno : res;
} }
int encfs_listxattr( const char *path, char *list, size_t size ) int encfs_listxattr(const char *path, char *list, size_t size) {
{
return withCipherPath("listxattr", path, _do_listxattr, return withCipherPath("listxattr", path, _do_listxattr,
make_tuple(list, size), true); make_tuple(list, size), true);
} }
int _do_removexattr(EncFS_Context *, const string &cyName, const char *name) int _do_removexattr(EncFS_Context *, const string &cyName, const char *name) {
{
#ifdef XATTR_ADD_OPT #ifdef XATTR_ADD_OPT
int options = 0; int options = 0;
int res = ::removexattr(cyName.c_str(), name, options); int res = ::removexattr(cyName.c_str(), name, options);
@ -793,10 +684,8 @@ int _do_removexattr(EncFS_Context *, const string &cyName, const char *name)
return (res == -1) ? -errno : res; return (res == -1) ? -errno : res;
} }
int encfs_removexattr( const char *path, const char *name ) int encfs_removexattr(const char *path, const char *name) {
{
return withCipherPath("removexattr", path, _do_removexattr, name); return withCipherPath("removexattr", path, _do_removexattr, name);
} }
#endif // HAVE_XATTR #endif // HAVE_XATTR

View File

@ -32,26 +32,22 @@
#ifndef linux #ifndef linux
#include <cerrno> #include <cerrno>
static __inline int setfsuid(uid_t uid) static __inline int setfsuid(uid_t uid) {
{
uid_t olduid = geteuid(); uid_t olduid = geteuid();
seteuid(uid); seteuid(uid);
if (errno != EINVAL) if (errno != EINVAL) errno = 0;
errno = 0;
return olduid; return olduid;
} }
static __inline int setfsgid(gid_t gid) static __inline int setfsgid(gid_t gid) {
{
gid_t oldgid = getegid(); gid_t oldgid = getegid();
setegid(gid); setegid(gid);
if (errno != EINVAL) if (errno != EINVAL) errno = 0;
errno = 0;
return oldgid; return oldgid;
} }
@ -72,8 +68,7 @@ int encfs_link(const char *from, const char *to);
int encfs_chmod(const char *path, mode_t mode); int encfs_chmod(const char *path, mode_t mode);
int encfs_chown(const char *path, uid_t uid, gid_t gid); int encfs_chown(const char *path, uid_t uid, gid_t gid);
int encfs_truncate(const char *path, off_t size); int encfs_truncate(const char *path, off_t size);
int encfs_ftruncate(const char *path, off_t size, int encfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi);
struct fuse_file_info *fi);
int encfs_utime(const char *path, struct utimbuf *buf); int encfs_utime(const char *path, struct utimbuf *buf);
int encfs_open(const char *path, struct fuse_file_info *info); int encfs_open(const char *path, struct fuse_file_info *info);
int encfs_release(const char *path, struct fuse_file_info *info); int encfs_release(const char *path, struct fuse_file_info *info);
@ -90,8 +85,8 @@ int encfs_fsync(const char *path, int flags, struct fuse_file_info *info);
#ifdef XATTR_ADD_OPT #ifdef XATTR_ADD_OPT
int encfs_setxattr(const char *path, const char *name, const char *value, int encfs_setxattr(const char *path, const char *name, const char *value,
size_t size, int flags, uint32_t position); size_t size, int flags, uint32_t position);
int encfs_getxattr( const char *path, const char *name, char *value, int encfs_getxattr(const char *path, const char *name, char *value, size_t size,
size_t size, uint32_t position ); uint32_t position);
#else #else
int encfs_setxattr(const char *path, const char *name, const char *value, int encfs_setxattr(const char *path, const char *name, const char *value,
size_t size, int flags); size_t size, int flags);
@ -106,4 +101,3 @@ int encfs_removexattr( const char *path, const char *name );
int encfs_utimens(const char *path, const struct timespec ts[2]); int encfs_utimens(const char *path, const struct timespec ts[2]);
#endif #endif

View File

@ -15,7 +15,6 @@
* more details. * more details.
*/ */
#include "encfs.h" #include "encfs.h"
#include "config.h" #include "config.h"
@ -67,16 +66,14 @@ static int cmd_cat( int argc, char **argv );
static int cmd_export(int argc, char **argv); static int cmd_export(int argc, char **argv);
static int cmd_showKey(int argc, char **argv); static int cmd_showKey(int argc, char **argv);
struct CommandOpts struct CommandOpts {
{
const char *name; const char *name;
int minOptions; int minOptions;
int maxOptions; int maxOptions;
int (*func)(int argc, char **argv); int (*func)(int argc, char **argv);
const char *argStr; const char *argStr;
const char *usageStr; const char *usageStr;
} commands[] = } commands[] = {
{
{"info", 1, 1, showInfo, "(root dir)", {"info", 1, 1, showInfo, "(root dir)",
// xgroup(usage) // xgroup(usage)
gettext_noop(" -- show information (Default command)")}, gettext_noop(" -- show information (Default command)")},
@ -88,7 +85,8 @@ struct CommandOpts
gettext_noop(" -- change password for volume")}, gettext_noop(" -- change password for volume")},
{"autopasswd", 1, 1, chpasswdAutomaticly, "(root dir)", {"autopasswd", 1, 1, chpasswdAutomaticly, "(root dir)",
// xgroup(usage) // xgroup(usage)
gettext_noop(" -- change password for volume, taking password" gettext_noop(
" -- change password for volume, taking password"
" from standard input.\n\tNo prompts are issued.")}, " from standard input.\n\tNo prompts are issued.")},
{"ls", 1, 2, cmd_ls, 0, 0}, {"ls", 1, 2, cmd_ls, 0, 0},
{"showcruft", 1, 1, cmd_showcruft, "(root dir)", {"showcruft", 1, 1, cmd_showcruft, "(root dir)",
@ -97,10 +95,12 @@ struct CommandOpts
{"cat", 2, 2, cmd_cat, "(root dir) path", {"cat", 2, 2, cmd_cat, "(root dir) path",
// xgroup(usage) // xgroup(usage)
gettext_noop(" -- decodes the file and cats it to standard out")}, gettext_noop(" -- decodes the file and cats it to standard out")},
{"decode", 1, 100, cmd_decode, "[--extpass=prog] (root dir) [encoded-name ...]", {"decode", 1, 100, cmd_decode,
"[--extpass=prog] (root dir) [encoded-name ...]",
// xgroup(usage) // xgroup(usage)
gettext_noop(" -- decodes name and prints plaintext version")}, gettext_noop(" -- decodes name and prints plaintext version")},
{"encode", 1, 100, cmd_encode, "[--extpass=prog] (root dir) [plaintext-name ...]", {"encode", 1, 100, cmd_encode,
"[--extpass=prog] (root dir) [plaintext-name ...]",
// xgroup(usage) // xgroup(usage)
gettext_noop(" -- encodes a filename and print result")}, gettext_noop(" -- encodes a filename and print result")},
{"export", 2, 2, cmd_export, "(root dir) path", {"export", 2, 2, cmd_export, "(root dir) path",
@ -109,26 +109,20 @@ struct CommandOpts
{"--version", 0, 0, showVersion, "", {"--version", 0, 0, showVersion, "",
// xgroup(usage) // xgroup(usage)
gettext_noop(" -- print version number and exit")}, gettext_noop(" -- print version number and exit")},
{0,0,0,0,0,0} {0, 0, 0, 0, 0, 0}};
};
static void usage(const char *name) {
cerr << format(_("encfsctl version %s")) % VERSION << "\n" << _("Usage:\n")
static
void usage(const char *name)
{
cerr << format(_("encfsctl version %s")) % VERSION << "\n"
<< _("Usage:\n")
// displays usage commands, eg "./encfs (root dir) ..." // displays usage commands, eg "./encfs (root dir) ..."
// xgroup(usage) // xgroup(usage)
<< format(_("%s (root dir)\n" << format(
" -- displays information about the filesystem, or \n")) % name; _("%s (root dir)\n"
" -- displays information about the filesystem, or \n")) %
name;
int offset = 0; int offset = 0;
while(commands[offset].name != 0) while (commands[offset].name != 0) {
{ if (commands[offset].argStr != 0) {
if( commands[offset].argStr != 0 )
{
cerr << "encfsctl " << commands[offset].name << " " cerr << "encfsctl " << commands[offset].name << " "
<< commands[offset].argStr << "\n" << commands[offset].argStr << "\n"
<< gettext(commands[offset].usageStr) << "\n"; << gettext(commands[offset].usageStr) << "\n";
@ -138,26 +132,20 @@ void usage(const char *name)
cerr << "\n" cerr << "\n"
// xgroup(usage) // xgroup(usage)
<< format(_("Example: \n%s info ~/.crypt\n")) % name << format(_("Example: \n%s info ~/.crypt\n")) % name << "\n";
<< "\n";
} }
static bool checkDir( string &rootDir ) static bool checkDir(string &rootDir) {
{ if (!isDirectory(rootDir.c_str())) {
if( !isDirectory( rootDir.c_str() )) cerr << format(_("directory %s does not exist.\n")) % rootDir.c_str();
{
cerr << format(_("directory %s does not exist.\n")) %
rootDir.c_str();
return false; return false;
} }
if(rootDir[ rootDir.length()-1 ] != '/') if (rootDir[rootDir.length() - 1] != '/') rootDir.append("/");
rootDir.append("/");
return true; return true;
} }
static int showVersion( int argc, char **argv ) static int showVersion(int argc, char **argv) {
{
(void)argc; (void)argc;
(void)argv; (void)argv;
// xgroup(usage) // xgroup(usage)
@ -166,19 +154,16 @@ static int showVersion( int argc, char **argv )
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
static int showInfo( int argc, char **argv ) static int showInfo(int argc, char **argv) {
{
(void)argc; (void)argc;
string rootDir = argv[1]; string rootDir = argv[1];
if( !checkDir( rootDir )) if (!checkDir(rootDir)) return EXIT_FAILURE;
return EXIT_FAILURE;
shared_ptr<EncFSConfig> config(new EncFSConfig); shared_ptr<EncFSConfig> config(new EncFSConfig);
ConfigType type = readConfig(rootDir, config); ConfigType type = readConfig(rootDir, config);
// show information stored in config.. // show information stored in config..
switch(type) switch (type) {
{
case Config_None: case Config_None:
// xgroup(diag) // xgroup(diag)
cout << _("Unable to load or parse config file\n"); cout << _("Unable to load or parse config file\n");
@ -190,25 +175,31 @@ static int showInfo( int argc, char **argv )
return EXIT_FAILURE; return EXIT_FAILURE;
case Config_V3: case Config_V3:
// xgroup(diag) // xgroup(diag)
cout << "\n" << format(_("Version 3 configuration; " cout << "\n" << format(
"created by %s\n")) % config->creator.c_str(); _("Version 3 configuration; "
"created by %s\n")) %
config->creator.c_str();
break; break;
case Config_V4: case Config_V4:
// xgroup(diag) // xgroup(diag)
cout << "\n" << format(_("Version 4 configuration; " cout << "\n" << format(
"created by %s\n")) % config->creator.c_str(); _("Version 4 configuration; "
"created by %s\n")) %
config->creator.c_str();
break; break;
case Config_V5: case Config_V5:
// xgroup(diag) // xgroup(diag)
cout << "\n" << format(_("Version 5 configuration; " cout << "\n" << format(
"created by %s (revision %i)\n")) % config->creator % _("Version 5 configuration; "
config->subVersion; "created by %s (revision %i)\n")) %
config->creator % config->subVersion;
break; break;
case Config_V6: case Config_V6:
// xgroup(diag) // xgroup(diag)
cout << "\n" << format(_("Version 6 configuration; " cout << "\n" << format(
"created by %s (revision %i)\n")) % config->creator % _("Version 6 configuration; "
config->subVersion; "created by %s (revision %i)\n")) %
config->creator % config->subVersion;
break; break;
} }
@ -217,29 +208,21 @@ static int showInfo( int argc, char **argv )
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
static RootPtr initRootInfo(int &argc, char ** &argv) static RootPtr initRootInfo(int &argc, char **&argv) {
{
RootPtr result; RootPtr result;
shared_ptr<EncFS_Opts> opts(new EncFS_Opts()); shared_ptr<EncFS_Opts> opts(new EncFS_Opts());
opts->createIfNotFound = false; opts->createIfNotFound = false;
opts->checkKey = false; opts->checkKey = false;
static struct option long_options[] = { static struct option long_options[] = {{"extpass", 1, 0, 'p'}, {0, 0, 0, 0}};
{"extpass", 1, 0, 'p'},
{0,0,0,0}
};
for(;;) for (;;) {
{
int option_index = 0; int option_index = 0;
int res = getopt_long( argc, argv, "", int res = getopt_long(argc, argv, "", long_options, &option_index);
long_options, &option_index); if (res == -1) break;
if(res == -1)
break;
switch(res) switch (res) {
{
case 'p': case 'p':
opts->passwordProgram.assign(optarg); opts->passwordProgram.assign(optarg);
break; break;
@ -252,18 +235,15 @@ static RootPtr initRootInfo(int &argc, char ** &argv)
argc -= optind; argc -= optind;
argv += optind; argv += optind;
if(argc == 0) if (argc == 0) {
{
cerr << _("Incorrect number of arguments") << "\n"; cerr << _("Incorrect number of arguments") << "\n";
} else } else {
{
opts->rootDir = string(argv[0]); opts->rootDir = string(argv[0]);
--argc; --argc;
++argv; ++argv;
if(checkDir( opts->rootDir )) if (checkDir(opts->rootDir)) result = initFS(NULL, opts);
result = initFS( NULL, opts );
if (!result) if (!result)
cerr << _("Unable to initialize encrypted filesystem - check path.\n"); cerr << _("Unable to initialize encrypted filesystem - check path.\n");
@ -272,13 +252,11 @@ static RootPtr initRootInfo(int &argc, char ** &argv)
return result; return result;
} }
static RootPtr initRootInfo(const char* crootDir) static RootPtr initRootInfo(const char *crootDir) {
{
string rootDir(crootDir); string rootDir(crootDir);
RootPtr result; RootPtr result;
if(checkDir( rootDir )) if (checkDir(rootDir)) {
{
shared_ptr<EncFS_Opts> opts(new EncFS_Opts()); shared_ptr<EncFS_Opts> opts(new EncFS_Opts());
opts->rootDir = rootDir; opts->rootDir = rootDir;
opts->createIfNotFound = false; opts->createIfNotFound = false;
@ -292,18 +270,16 @@ static RootPtr initRootInfo(const char* crootDir)
return result; return result;
} }
static int cmd_showKey( int argc, char **argv ) static int cmd_showKey(int argc, char **argv) {
{
(void)argc; (void)argc;
RootPtr rootInfo = initRootInfo(argv[1]); RootPtr rootInfo = initRootInfo(argv[1]);
if (!rootInfo) if (!rootInfo)
return EXIT_FAILURE; return EXIT_FAILURE;
else else {
{
// encode with itself // encode with itself
string b64Key = rootInfo->cipher->encodeAsString( string b64Key = rootInfo->cipher->encodeAsString(rootInfo->volumeKey,
rootInfo->volumeKey, rootInfo->volumeKey ); rootInfo->volumeKey);
cout << b64Key << "\n"; cout << b64Key << "\n";
@ -311,71 +287,55 @@ static int cmd_showKey( int argc, char **argv )
} }
} }
static int cmd_decode( int argc, char **argv ) static int cmd_decode(int argc, char **argv) {
{
RootPtr rootInfo = initRootInfo(argc, argv); RootPtr rootInfo = initRootInfo(argc, argv);
if(!rootInfo) if (!rootInfo) return EXIT_FAILURE;
return EXIT_FAILURE;
if(argc > 0) if (argc > 0) {
{ for (int i = 0; i < argc; ++i) {
for(int i=0; i<argc; ++i)
{
string name = rootInfo->root->plainPath(argv[i]); string name = rootInfo->root->plainPath(argv[i]);
cout << name << "\n"; cout << name << "\n";
} }
} else } else {
{
char buf[PATH_MAX + 1]; char buf[PATH_MAX + 1];
while(cin.getline(buf,PATH_MAX)) while (cin.getline(buf, PATH_MAX)) {
{
cout << rootInfo->root->plainPath(buf) << "\n"; cout << rootInfo->root->plainPath(buf) << "\n";
} }
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
static int cmd_encode( int argc, char **argv ) static int cmd_encode(int argc, char **argv) {
{
RootPtr rootInfo = initRootInfo(argc, argv); RootPtr rootInfo = initRootInfo(argc, argv);
if(!rootInfo) if (!rootInfo) return EXIT_FAILURE;
return EXIT_FAILURE;
if(argc > 0) if (argc > 0) {
{ for (int i = 0; i < argc; ++i) {
for(int i=0; i<argc; ++i)
{
string name = rootInfo->root->cipherPathWithoutRoot(argv[i]); string name = rootInfo->root->cipherPathWithoutRoot(argv[i]);
cout << name << "\n"; cout << name << "\n";
} }
} else } else {
{
char buf[PATH_MAX + 1]; char buf[PATH_MAX + 1];
while(cin.getline(buf,PATH_MAX)) while (cin.getline(buf, PATH_MAX)) {
{
cout << rootInfo->root->cipherPathWithoutRoot(buf) << "\n"; cout << rootInfo->root->cipherPathWithoutRoot(buf) << "\n";
} }
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
static int cmd_ls( int argc, char **argv ) static int cmd_ls(int argc, char **argv) {
{
(void)argc; (void)argc;
RootPtr rootInfo = initRootInfo(argv[1]); RootPtr rootInfo = initRootInfo(argv[1]);
if(!rootInfo) if (!rootInfo) return EXIT_FAILURE;
return EXIT_FAILURE;
// show files in directory // show files in directory
{ {
DirTraverse dt = rootInfo->root->openDir("/"); DirTraverse dt = rootInfo->root->openDir("/");
if(dt.valid()) if (dt.valid()) {
{
for (string name = dt.nextPlaintextName(); !name.empty(); for (string name = dt.nextPlaintextName(); !name.empty();
name = dt.nextPlaintextName()) name = dt.nextPlaintextName()) {
{
shared_ptr<FileNode> fnode = shared_ptr<FileNode> fnode =
rootInfo->root->lookupNode(name.c_str(), "encfsctl-ls"); rootInfo->root->lookupNode(name.c_str(), "encfsctl-ls");
struct stat stbuf; struct stat stbuf;
@ -386,8 +346,7 @@ static int cmd_ls( int argc, char **argv )
stm.tm_year += 1900; stm.tm_year += 1900;
// TODO: when I add "%s" to the end and name.c_str(), I get a // TODO: when I add "%s" to the end and name.c_str(), I get a
// seg fault from within strlen. Why ??? // seg fault from within strlen. Why ???
printf("%11i %4i-%02i-%02i %02i:%02i:%02i %s\n", printf("%11i %4i-%02i-%02i %02i:%02i:%02i %s\n", int(stbuf.st_size),
int(stbuf.st_size),
int(stm.tm_year), int(stm.tm_mon), int(stm.tm_mday), int(stm.tm_year), int(stm.tm_mon), int(stm.tm_mday),
int(stm.tm_hour), int(stm.tm_min), int(stm.tm_sec), int(stm.tm_hour), int(stm.tm_min), int(stm.tm_sec),
name.c_str()); name.c_str());
@ -400,66 +359,55 @@ static int cmd_ls( int argc, char **argv )
// apply an operation to every block in the file // apply an operation to every block in the file
template <typename T> template <typename T>
int processContents( const shared_ptr<EncFS_Root> &rootInfo, int processContents(const shared_ptr<EncFS_Root> &rootInfo, const char *path,
const char *path, T &op ) T &op) {
{
int errCode = 0; int errCode = 0;
shared_ptr<FileNode> node = rootInfo->root->openNode( path, "encfsctl", shared_ptr<FileNode> node =
O_RDONLY, &errCode ); rootInfo->root->openNode(path, "encfsctl", O_RDONLY, &errCode);
if(!node) if (!node) {
{
// try treating filename as an enciphered path // try treating filename as an enciphered path
string plainName = rootInfo->root->plainPath(path); string plainName = rootInfo->root->plainPath(path);
node = rootInfo->root->lookupNode(plainName.c_str(), "encfsctl"); node = rootInfo->root->lookupNode(plainName.c_str(), "encfsctl");
if(node) if (node) {
{
errCode = node->open(O_RDONLY); errCode = node->open(O_RDONLY);
if(errCode < 0) if (errCode < 0) node.reset();
node.reset();
} }
} }
if(!node) if (!node) {
{
cerr << "unable to open " << path << "\n"; cerr << "unable to open " << path << "\n";
return errCode; return errCode;
} else } else {
{
unsigned char buf[512]; unsigned char buf[512];
int blocks = (node->getSize() + sizeof(buf) - 1) / sizeof(buf); int blocks = (node->getSize() + sizeof(buf) - 1) / sizeof(buf);
// read all the data in blocks // read all the data in blocks
for(int i=0; i<blocks; ++i) for (int i = 0; i < blocks; ++i) {
{
int bytes = node->read(i * sizeof(buf), buf, sizeof(buf)); int bytes = node->read(i * sizeof(buf), buf, sizeof(buf));
int res = op(buf, bytes); int res = op(buf, bytes);
if(res < 0) if (res < 0) return res;
return res;
} }
} }
return 0; return 0;
} }
class WriteOutput class WriteOutput {
{
int _fd; int _fd;
public: public:
WriteOutput(int fd) { _fd = fd; } WriteOutput(int fd) { _fd = fd; }
~WriteOutput() { close(_fd); } ~WriteOutput() { close(_fd); }
int operator()(const void *buf, int count) int operator()(const void *buf, int count) {
{
return (int)write(_fd, buf, count); return (int)write(_fd, buf, count);
} }
}; };
static int cmd_cat( int argc, char **argv ) static int cmd_cat(int argc, char **argv) {
{
(void)argc; (void)argc;
RootPtr rootInfo = initRootInfo(argv[1]); RootPtr rootInfo = initRootInfo(argv[1]);
if(!rootInfo) if (!rootInfo) return EXIT_FAILURE;
return EXIT_FAILURE;
const char *path = argv[2]; const char *path = argv[2];
WriteOutput output(STDOUT_FILENO); WriteOutput output(STDOUT_FILENO);
@ -469,13 +417,11 @@ static int cmd_cat( int argc, char **argv )
} }
static int copyLink(const struct stat &stBuf, static int copyLink(const struct stat &stBuf,
const shared_ptr<EncFS_Root> &rootInfo, const shared_ptr<EncFS_Root> &rootInfo, const string &cpath,
const string &cpath, const string &destName ) const string &destName) {
{
scoped_array<char> buf(new char[stBuf.st_size + 1]); scoped_array<char> buf(new char[stBuf.st_size + 1]);
int res = ::readlink(cpath.c_str(), buf.get(), stBuf.st_size); int res = ::readlink(cpath.c_str(), buf.get(), stBuf.st_size);
if(res == -1) if (res == -1) {
{
cerr << "unable to readlink of " << cpath << "\n"; cerr << "unable to readlink of " << cpath << "\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -484,46 +430,36 @@ static int copyLink(const struct stat &stBuf,
string decodedLink = rootInfo->root->plainPath(buf.get()); string decodedLink = rootInfo->root->plainPath(buf.get());
res = ::symlink(decodedLink.c_str(), destName.c_str()); res = ::symlink(decodedLink.c_str(), destName.c_str());
if(res == -1) if (res == -1) {
{ cerr << "unable to create symlink for " << cpath << " to " << decodedLink
cerr << "unable to create symlink for " << cpath << "\n";
<< " to " << decodedLink << "\n";
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
static int copyContents(const shared_ptr<EncFS_Root> &rootInfo, static int copyContents(const shared_ptr<EncFS_Root> &rootInfo,
const char* encfsName, const char* targetName) const char *encfsName, const char *targetName) {
{ shared_ptr<FileNode> node = rootInfo->root->lookupNode(encfsName, "encfsctl");
shared_ptr<FileNode> node =
rootInfo->root->lookupNode( encfsName, "encfsctl" );
if(!node) if (!node) {
{
cerr << "unable to open " << encfsName << "\n"; cerr << "unable to open " << encfsName << "\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} else } else {
{
struct stat st; struct stat st;
if(node->getAttr(&st) != 0) if (node->getAttr(&st) != 0) return EXIT_FAILURE;
return EXIT_FAILURE;
if((st.st_mode & S_IFLNK) == S_IFLNK) if ((st.st_mode & S_IFLNK) == S_IFLNK) {
{
string d = rootInfo->root->cipherPath(encfsName); string d = rootInfo->root->cipherPath(encfsName);
char linkContents[PATH_MAX + 2]; char linkContents[PATH_MAX + 2];
if(readlink (d.c_str(), linkContents, PATH_MAX + 1) <= 0) if (readlink(d.c_str(), linkContents, PATH_MAX + 1) <= 0) {
{
cerr << "unable to read link " << encfsName << "\n"; cerr << "unable to read link " << encfsName << "\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} }
symlink(rootInfo->root->plainPath(linkContents).c_str(), symlink(rootInfo->root->plainPath(linkContents).c_str(), targetName);
targetName); } else {
} else
{
int outfd = creat(targetName, st.st_mode); int outfd = creat(targetName, st.st_mode);
WriteOutput output(outfd); WriteOutput output(outfd);
@ -533,8 +469,7 @@ static int copyContents(const shared_ptr<EncFS_Root> &rootInfo,
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
static bool endsWith(const string &str, char ch) static bool endsWith(const string &str, char ch) {
{
if (str.empty()) if (str.empty())
return false; return false;
else else
@ -542,12 +477,9 @@ static bool endsWith(const string &str, char ch)
} }
static int traverseDirs(const shared_ptr<EncFS_Root> &rootInfo, static int traverseDirs(const shared_ptr<EncFS_Root> &rootInfo,
string volumeDir, string destDir) string volumeDir, string destDir) {
{ if (!endsWith(volumeDir, '/')) volumeDir.append("/");
if(!endsWith(volumeDir, '/')) if (!endsWith(destDir, '/')) destDir.append("/");
volumeDir.append("/");
if(!endsWith(destDir, '/'))
destDir.append("/");
// Lookup directory node so we can create a destination directory // Lookup directory node so we can create a destination directory
// with the same permissions // with the same permissions
@ -555,63 +487,49 @@ static int traverseDirs(const shared_ptr<EncFS_Root> &rootInfo,
struct stat st; struct stat st;
shared_ptr<FileNode> dirNode = shared_ptr<FileNode> dirNode =
rootInfo->root->lookupNode(volumeDir.c_str(), "encfsctl"); rootInfo->root->lookupNode(volumeDir.c_str(), "encfsctl");
if(dirNode->getAttr(&st)) if (dirNode->getAttr(&st)) return EXIT_FAILURE;
return EXIT_FAILURE;
mkdir(destDir.c_str(), st.st_mode); mkdir(destDir.c_str(), st.st_mode);
} }
// show files in directory // show files in directory
DirTraverse dt = rootInfo->root->openDir(volumeDir.c_str()); DirTraverse dt = rootInfo->root->openDir(volumeDir.c_str());
if(dt.valid()) if (dt.valid()) {
{
for (string name = dt.nextPlaintextName(); !name.empty(); for (string name = dt.nextPlaintextName(); !name.empty();
name = dt.nextPlaintextName()) name = dt.nextPlaintextName()) {
{
// Recurse to subdirectories // Recurse to subdirectories
if(name != "." && name != "..") if (name != "." && name != "..") {
{
string plainPath = volumeDir + name; string plainPath = volumeDir + name;
string cpath = rootInfo->root->cipherPath(plainPath.c_str()); string cpath = rootInfo->root->cipherPath(plainPath.c_str());
string destName = destDir + name; string destName = destDir + name;
int r = EXIT_SUCCESS; int r = EXIT_SUCCESS;
struct stat stBuf; struct stat stBuf;
if( !lstat( cpath.c_str(), &stBuf )) if (!lstat(cpath.c_str(), &stBuf)) {
{ if (S_ISDIR(stBuf.st_mode)) {
if( S_ISDIR( stBuf.st_mode ) ) traverseDirs(rootInfo, (plainPath + '/').c_str(), destName + '/');
{ } else if (S_ISLNK(stBuf.st_mode)) {
traverseDirs(rootInfo, (plainPath + '/').c_str(),
destName + '/');
} else if( S_ISLNK( stBuf.st_mode ))
{
r = copyLink(stBuf, rootInfo, cpath, destName); r = copyLink(stBuf, rootInfo, cpath, destName);
} else } else {
{ r = copyContents(rootInfo, plainPath.c_str(), destName.c_str());
r = copyContents(rootInfo, plainPath.c_str(),
destName.c_str());
} }
} else } else {
{
r = EXIT_FAILURE; r = EXIT_FAILURE;
} }
if(r != EXIT_SUCCESS) if (r != EXIT_SUCCESS) return r;
return r;
} }
} }
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
static int cmd_export( int argc, char **argv ) static int cmd_export(int argc, char **argv) {
{
(void)argc; (void)argc;
RootPtr rootInfo = initRootInfo(argv[1]); RootPtr rootInfo = initRootInfo(argv[1]);
if(!rootInfo) if (!rootInfo) return EXIT_FAILURE;
return EXIT_FAILURE;
string destDir = argv[2]; string destDir = argv[2];
// if the dir doesn't exist, then create it (with user permission) // if the dir doesn't exist, then create it (with user permission)
@ -621,22 +539,18 @@ static int cmd_export( int argc, char **argv )
return traverseDirs(rootInfo, "/", destDir); return traverseDirs(rootInfo, "/", destDir);
} }
int showcruft( const shared_ptr<EncFS_Root> &rootInfo, const char *dirName ) int showcruft(const shared_ptr<EncFS_Root> &rootInfo, const char *dirName) {
{
int found = 0; int found = 0;
DirTraverse dt = rootInfo->root->openDir(dirName); DirTraverse dt = rootInfo->root->openDir(dirName);
if(dt.valid()) if (dt.valid()) {
{
bool showedDir = false; bool showedDir = false;
for (string name = dt.nextInvalid(); !name.empty(); for (string name = dt.nextInvalid(); !name.empty();
name = dt.nextInvalid()) name = dt.nextInvalid()) {
{
string cpath = rootInfo->root->cipherPath(dirName); string cpath = rootInfo->root->cipherPath(dirName);
cpath += '/'; cpath += '/';
cpath += name; cpath += name;
if(!showedDir) if (!showedDir) {
{
// just before showing a list of files in a directory // just before showing a list of files in a directory
cout << format(_("In directory %s: \n")) % dirName; cout << format(_("In directory %s: \n")) % dirName;
showedDir = true; showedDir = true;
@ -647,13 +561,10 @@ int showcruft( const shared_ptr<EncFS_Root> &rootInfo, const char *dirName )
// now go back and look for directories to recurse into.. // now go back and look for directories to recurse into..
dt = rootInfo->root->openDir(dirName); dt = rootInfo->root->openDir(dirName);
if(dt.valid()) if (dt.valid()) {
{
for (string name = dt.nextPlaintextName(); !name.empty(); for (string name = dt.nextPlaintextName(); !name.empty();
name = dt.nextPlaintextName()) name = dt.nextPlaintextName()) {
{ if (name == "." || name == "..") continue;
if( name == "." || name == "..")
continue;
string plainPath = dirName; string plainPath = dirName;
plainPath += '/'; plainPath += '/';
@ -674,45 +585,38 @@ int showcruft( const shared_ptr<EncFS_Root> &rootInfo, const char *dirName )
iterate recursively through the filesystem and print out names of files iterate recursively through the filesystem and print out names of files
which have filenames which cannot be decoded with the given key.. which have filenames which cannot be decoded with the given key..
*/ */
static int cmd_showcruft( int argc, char **argv ) static int cmd_showcruft(int argc, char **argv) {
{
(void)argc; (void)argc;
RootPtr rootInfo = initRootInfo(argv[1]); RootPtr rootInfo = initRootInfo(argv[1]);
if(!rootInfo) if (!rootInfo) return EXIT_FAILURE;
return EXIT_FAILURE;
int filesFound = showcruft(rootInfo, "/"); int filesFound = showcruft(rootInfo, "/");
cerr << format( cerr << format(ngettext("Found %i invalid file.", "Found %i invalid files.",
ngettext("Found %i invalid file.", "Found %i invalid files.", filesFound)) %
filesFound)) % filesFound << "\n"; filesFound << "\n";
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
static int do_chpasswd( bool useStdin, bool annotate, int argc, char **argv ) static int do_chpasswd(bool useStdin, bool annotate, int argc, char **argv) {
{
(void)argc; (void)argc;
string rootDir = argv[1]; string rootDir = argv[1];
if( !checkDir( rootDir )) if (!checkDir(rootDir)) return EXIT_FAILURE;
return EXIT_FAILURE;
shared_ptr<EncFSConfig> config(new EncFSConfig); shared_ptr<EncFSConfig> config(new EncFSConfig);
ConfigType cfgType = readConfig(rootDir, config); ConfigType cfgType = readConfig(rootDir, config);
if(cfgType == Config_None) if (cfgType == Config_None) {
{
cout << _("Unable to load or parse config file\n"); cout << _("Unable to load or parse config file\n");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
// instanciate proper cipher // instanciate proper cipher
shared_ptr<Cipher> cipher = Cipher::New( shared_ptr<Cipher> cipher = Cipher::New(config->cipherIface, config->keySize);
config->cipherIface, config->keySize ); if (!cipher) {
if(!cipher)
{
cout << format(_("Unable to find specified cipher \"%s\"\n")) % cout << format(_("Unable to find specified cipher \"%s\"\n")) %
config->cipherIface.name(); config->cipherIface.name();
return EXIT_FAILURE; return EXIT_FAILURE;
@ -720,18 +624,15 @@ static int do_chpasswd( bool useStdin, bool annotate, int argc, char **argv )
// ask for existing password // ask for existing password
cout << _("Enter current Encfs password\n"); cout << _("Enter current Encfs password\n");
if (annotate) if (annotate) cerr << "$PROMPT$ passwd" << endl;
cerr << "$PROMPT$ passwd" << endl;
CipherKey userKey = config->getUserKey(useStdin); CipherKey userKey = config->getUserKey(useStdin);
if(!userKey) if (!userKey) return EXIT_FAILURE;
return EXIT_FAILURE;
// decode volume key using user key -- at this point we detect an incorrect // decode volume key using user key -- at this point we detect an incorrect
// password if the key checksum does not match (causing readKey to fail). // password if the key checksum does not match (causing readKey to fail).
CipherKey volumeKey = cipher->readKey(config->getKeyData(), userKey); CipherKey volumeKey = cipher->readKey(config->getKeyData(), userKey);
if(!volumeKey) if (!volumeKey) {
{
cout << _("Invalid password\n"); cout << _("Invalid password\n");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -742,19 +643,15 @@ static int do_chpasswd( bool useStdin, bool annotate, int argc, char **argv )
// reinitialize salt and iteration count // reinitialize salt and iteration count
config->kdfIterations = 0; // generate new config->kdfIterations = 0; // generate new
if( useStdin ) if (useStdin) {
{ if (annotate) cerr << "$PROMPT$ new_passwd" << endl;
if (annotate)
cerr << "$PROMPT$ new_passwd" << endl;
userKey = config->getUserKey(true); userKey = config->getUserKey(true);
} } else
else
userKey = config->getNewUserKey(); userKey = config->getNewUserKey();
// re-encode the volume key using the new user key and write it out.. // re-encode the volume key using the new user key and write it out..
int result = EXIT_FAILURE; int result = EXIT_FAILURE;
if(userKey) if (userKey) {
{
int encodedKeySize = cipher->encodedKeySize(); int encodedKeySize = cipher->encodedKeySize();
unsigned char *keyBuf = new unsigned char[encodedKeySize]; unsigned char *keyBuf = new unsigned char[encodedKeySize];
@ -765,17 +662,14 @@ static int do_chpasswd( bool useStdin, bool annotate, int argc, char **argv )
config->assignKeyData(keyBuf, encodedKeySize); config->assignKeyData(keyBuf, encodedKeySize);
delete[] keyBuf; delete[] keyBuf;
if(saveConfig( cfgType, rootDir, config )) if (saveConfig(cfgType, rootDir, config)) {
{
// password modified -- changes volume key of filesystem.. // password modified -- changes volume key of filesystem..
cout << _("Volume Key successfully updated.\n"); cout << _("Volume Key successfully updated.\n");
result = EXIT_SUCCESS; result = EXIT_SUCCESS;
} else } else {
{
cout << _("Error saving modified config file.\n"); cout << _("Error saving modified config file.\n");
} }
} else } else {
{
cout << _("Error creating key\n"); cout << _("Error creating key\n");
} }
@ -784,19 +678,15 @@ static int do_chpasswd( bool useStdin, bool annotate, int argc, char **argv )
return result; return result;
} }
static int chpasswd( int argc, char **argv ) static int chpasswd(int argc, char **argv) {
{
return do_chpasswd(false, false, argc, argv); return do_chpasswd(false, false, argc, argv);
} }
static int chpasswdAutomaticly( int argc, char **argv ) static int chpasswdAutomaticly(int argc, char **argv) {
{
return do_chpasswd(true, false, argc, argv); return do_chpasswd(true, false, argc, argv);
} }
int main(int argc, char **argv) {
int main(int argc, char **argv)
{
RLogInit(argc, argv); RLogInit(argc, argv);
#if defined(ENABLE_NLS) && defined(LOCALEDIR) #if defined(ENABLE_NLS) && defined(LOCALEDIR)
@ -817,38 +707,29 @@ int main(int argc, char **argv)
// slog->subscribeTo( GetGlobalChannel("debug") ); // slog->subscribeTo( GetGlobalChannel("debug") );
#endif #endif
if(argc < 2) if (argc < 2) {
{
usage(argv[0]); usage(argv[0]);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if(argc == 2 && !(*argv[1] == '-' && *(argv[1]+1) == '-')) if (argc == 2 && !(*argv[1] == '-' && *(argv[1] + 1) == '-')) {
{
// default command when only 1 argument given -- treat the argument as // default command when only 1 argument given -- treat the argument as
// a directory.. // a directory..
return showInfo(argc, argv); return showInfo(argc, argv);
} else } else {
{
// find the specified command // find the specified command
int offset = 0; int offset = 0;
while(commands[offset].name != 0) while (commands[offset].name != 0) {
{ if (!strcmp(argv[1], commands[offset].name)) break;
if(!strcmp( argv[1], commands[offset].name ))
break;
++offset; ++offset;
} }
if(commands[offset].name == 0) if (commands[offset].name == 0) {
{
cerr << format(_("invalid command: \"%s\"")) % argv[1] << "\n"; cerr << format(_("invalid command: \"%s\"")) % argv[1] << "\n";
} else } else {
{
if ((argc - 2 < commands[offset].minOptions) || if ((argc - 2 < commands[offset].minOptions) ||
(argc-2 > commands[offset].maxOptions)) (argc - 2 > commands[offset].maxOptions)) {
{ cerr << format(_("Incorrect number of arguments for command \"%s\"")) %
cerr << format(
_("Incorrect number of arguments for command \"%s\"")) %
argv[1] << "\n"; argv[1] << "\n";
} else } else
return (*commands[offset].func)(argc - 1, argv + 1); return (*commands[offset].func)(argc - 1, argv + 1);

View File

@ -28,5 +28,3 @@
#define _(STR) gettext(STR) #define _(STR) gettext(STR)
#endif #endif

View File

@ -59,10 +59,7 @@ extern "C" void fuse_unmount_compat22(const char *mountpoint);
#define fuse_unmount fuse_unmount_compat22 #define fuse_unmount fuse_unmount_compat22
#ifndef MAX #ifndef MAX
inline static int MAX(int a, int b) inline static int MAX(int a, int b) { return (a > b) ? a : b; }
{
return (a > b) ? a : b;
}
#endif #endif
using namespace std; using namespace std;
@ -74,8 +71,7 @@ using boost::scoped_ptr;
// Maximum number of arguments that we're going to pass on to fuse. Doesn't // Maximum number of arguments that we're going to pass on to fuse. Doesn't
// affect how many arguments we can handle, just how many we can pass on.. // affect how many arguments we can handle, just how many we can pass on..
const int MaxFuseArgs = 32; const int MaxFuseArgs = 32;
struct EncFS_Args struct EncFS_Args {
{
string mountPoint; // where to make filesystem visible string mountPoint; // where to make filesystem visible
bool isDaemon; // true == spawn in background, log to syslog bool isDaemon; // true == spawn in background, log to syslog
bool isThreaded; // true == threaded bool isThreaded; // true == threaded
@ -90,13 +86,11 @@ struct EncFS_Args
// In case someone sends me a log dump, I want to know how what options are // In case someone sends me a log dump, I want to know how what options are
// in effect. Not internationalized, since it is something that is mostly // in effect. Not internationalized, since it is something that is mostly
// useful for me! // useful for me!
string toString() string toString() {
{
ostringstream ss; ostringstream ss;
ss << (isDaemon ? "(daemon) " : "(fg) "); ss << (isDaemon ? "(daemon) " : "(fg) ");
ss << (isThreaded ? "(threaded) " : "(UP) "); ss << (isThreaded ? "(threaded) " : "(UP) ");
if(idleTimeout > 0) if (idleTimeout > 0) ss << "(timeout " << idleTimeout << ") ";
ss << "(timeout " << idleTimeout << ") ";
if (opts->checkKey) ss << "(keyCheck) "; if (opts->checkKey) ss << "(keyCheck) ";
if (opts->forceDecode) ss << "(forceDecode) "; if (opts->forceDecode) ss << "(forceDecode) ";
if (opts->ownerCreate) ss << "(ownerCreate) "; if (opts->ownerCreate) ss << "(ownerCreate) ";
@ -105,45 +99,49 @@ struct EncFS_Args
if (opts->reverseEncryption) ss << "(reverseEncryption) "; if (opts->reverseEncryption) ss << "(reverseEncryption) ";
if (opts->mountOnDemand) ss << "(mountOnDemand) "; if (opts->mountOnDemand) ss << "(mountOnDemand) ";
if (opts->delayMount) ss << "(delayMount) "; if (opts->delayMount) ss << "(delayMount) ";
for(int i=0; i<fuseArgc; ++i) for (int i = 0; i < fuseArgc; ++i) ss << fuseArgv[i] << ' ';
ss << fuseArgv[i] << ' ';
return ss.str(); return ss.str();
} }
EncFS_Args() EncFS_Args() : opts(new EncFS_Opts()) {}
: opts( new EncFS_Opts() )
{
}
}; };
static int oldStderr = STDERR_FILENO; static int oldStderr = STDERR_FILENO;
static static void usage(const char *name) {
void usage(const char *name)
{
// xgroup(usage) // xgroup(usage)
cerr << format( _("Build: encfs version %s")) % VERSION cerr << format(_("Build: encfs version %s")) % VERSION << "\n\n"
<< "\n\n"
// xgroup(usage) // xgroup(usage)
<< format(_("Usage: %s [options] rootDir mountPoint [-- [FUSE Mount Options]]")) % name << "\n\n" << format(
_("Usage: %s [options] rootDir mountPoint [-- [FUSE Mount "
"Options]]")) %
name << "\n\n"
// xgroup(usage) // xgroup(usage)
<< _("Common Options:\n" << _("Common Options:\n"
" -H\t\t\t" "show optional FUSE Mount Options\n" " -H\t\t\t"
" -s\t\t\t" "disable multithreaded operation\n" "show optional FUSE Mount Options\n"
" -f\t\t\t" "run in foreground (don't spawn daemon).\n" " -s\t\t\t"
"disable multithreaded operation\n"
" -f\t\t\t"
"run in foreground (don't spawn daemon).\n"
"\t\t\tError messages will be sent to stderr\n" "\t\t\tError messages will be sent to stderr\n"
"\t\t\tinstead of syslog.\n") "\t\t\tinstead of syslog.\n")
// xgroup(usage) // xgroup(usage)
<< _(" -v, --verbose\t\t" "verbose: output encfs debug messages\n" << _(" -v, --verbose\t\t"
" -i, --idle=MINUTES\t""Auto unmount after period of inactivity\n" "verbose: output encfs debug messages\n"
" --anykey\t\t" "Do not verify correct key is being used\n" " -i, --idle=MINUTES\t"
" --forcedecode\t\t" "decode data even if an error is detected\n" "Auto unmount after period of inactivity\n"
" --anykey\t\t"
"Do not verify correct key is being used\n"
" --forcedecode\t\t"
"decode data even if an error is detected\n"
"\t\t\t(for filesystems using MAC block headers)\n") "\t\t\t(for filesystems using MAC block headers)\n")
<< _(" --public\t\t" "act as a typical multi-user filesystem\n" << _(" --public\t\t"
"\t\t\t(encfs must be run as root)\n") "act as a typical multi-user filesystem\n"
<< _(" --reverse\t\t" "reverse encryption\n") "\t\t\t(encfs must be run as root)\n") << _(" --reverse\t\t"
"reverse encryption\n")
// xgroup(usage) // xgroup(usage)
<< _(" --extpass=program\tUse external program for password prompt\n" << _(" --extpass=program\tUse external program for password prompt\n"
@ -152,13 +150,10 @@ void usage(const char *name)
" encfs ~/.crypt ~/crypt\n" " encfs ~/.crypt ~/crypt\n"
"\n") "\n")
// xgroup(usage) // xgroup(usage)
<< _("For more information, see the man page encfs(1)") << "\n" << _("For more information, see the man page encfs(1)") << "\n" << endl;
<< endl;
} }
static static void FuseUsage() {
void FuseUsage()
{
// xgroup(usage) // xgroup(usage)
cerr << _("encfs [options] rootDir mountPoint -- [FUSE Mount Options]\n" cerr << _("encfs [options] rootDir mountPoint -- [FUSE Mount Options]\n"
"valid FUSE Mount Options follow:\n") << endl; "valid FUSE Mount Options follow:\n") << endl;
@ -168,22 +163,20 @@ void FuseUsage()
fuse_main(argc, const_cast<char **>(argv), (fuse_operations *)NULL, NULL); fuse_main(argc, const_cast<char **>(argv), (fuse_operations *)NULL, NULL);
} }
#define PUSHARG(ARG) do { \ #define PUSHARG(ARG) \
do { \
rAssert(out->fuseArgc < MaxFuseArgs); \ rAssert(out->fuseArgc < MaxFuseArgs); \
out->fuseArgv[out->fuseArgc++] = (ARG); } while(0) out->fuseArgv[out->fuseArgc++] = (ARG); \
} while (0)
static static string slashTerminate(const string &src) {
string slashTerminate( const string &src )
{
string result = src; string result = src;
if( result[ result.length()-1 ] != '/' ) if (result[result.length() - 1] != '/') result.append("/");
result.append( "/" );
return result; return result;
} }
static static bool processArgs(int argc, char *argv[],
bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out) const shared_ptr<EncFS_Args> &out) {
{
// set defaults // set defaults
out->isDaemon = true; out->isDaemon = true;
out->isThreaded = true; out->isThreaded = true;
@ -230,11 +223,9 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
{"reverse", 0, 0, 'r'}, // reverse encryption {"reverse", 0, 0, 'r'}, // reverse encryption
{"standard", 0, 0, '1'}, // standard configuration {"standard", 0, 0, '1'}, // standard configuration
{"paranoia", 0, 0, '2'}, // standard configuration {"paranoia", 0, 0, '2'}, // standard configuration
{0,0,0,0} {0, 0, 0, 0}};
};
while (1) while (1) {
{
int option_index = 0; int option_index = 0;
// 's' : single-threaded mode // 's' : single-threaded mode
@ -245,14 +236,12 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
// 'm' : mount-on-demand // 'm' : mount-on-demand
// 'S' : password from stdin // 'S' : password from stdin
// 'o' : arguments meant for fuse // 'o' : arguments meant for fuse
int res = getopt_long( argc, argv, "HsSfvdmi:o:", int res =
long_options, &option_index); getopt_long(argc, argv, "HsSfvdmi:o:", long_options, &option_index);
if(res == -1) if (res == -1) break;
break;
switch( res ) switch (res) {
{
case '1': case '1':
out->opts->configMode = Config_Standard; out->opts->configMode = Config_Standard;
break; break;
@ -311,8 +300,7 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
case 'P': case 'P':
if (geteuid() != 0) if (geteuid() != 0)
rWarning(_("option '--public' ignored for non-root user")); rWarning(_("option '--public' ignored for non-root user"));
else else {
{
out->opts->ownerCreate = true; out->opts->ownerCreate = true;
// add 'allow_other' option // add 'allow_other' option
// add 'default_permissions' option (default) // add 'default_permissions' option (default)
@ -341,11 +329,9 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
} }
} }
if(!out->isThreaded) if (!out->isThreaded) PUSHARG("-s");
PUSHARG("-s");
if(useDefaultFlags) if (useDefaultFlags) {
{
PUSHARG("-o"); PUSHARG("-o");
PUSHARG("use_ino"); PUSHARG("use_ino");
PUSHARG("-o"); PUSHARG("-o");
@ -354,24 +340,20 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
// we should have at least 2 arguments left over - the source directory and // we should have at least 2 arguments left over - the source directory and
// the mount point. // the mount point.
if(optind+2 <= argc) if (optind + 2 <= argc) {
{
out->opts->rootDir = slashTerminate(argv[optind++]); out->opts->rootDir = slashTerminate(argv[optind++]);
out->mountPoint = argv[optind++]; out->mountPoint = argv[optind++];
} else } else {
{
// no mount point specified // no mount point specified
rWarning(_("Missing one or more arguments, aborting.")); rWarning(_("Missing one or more arguments, aborting."));
return false; return false;
} }
// If there are still extra unparsed arguments, pass them onto FUSE.. // If there are still extra unparsed arguments, pass them onto FUSE..
if(optind < argc) if (optind < argc) {
{
rAssert(out->fuseArgc < MaxFuseArgs); rAssert(out->fuseArgc < MaxFuseArgs);
while(optind < argc) while (optind < argc) {
{
rAssert(out->fuseArgc < MaxFuseArgs); rAssert(out->fuseArgc < MaxFuseArgs);
out->fuseArgv[out->fuseArgc++] = argv[optind]; out->fuseArgv[out->fuseArgc++] = argv[optind];
++optind; ++optind;
@ -379,27 +361,21 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
} }
// sanity check // sanity check
if(out->isDaemon && if (out->isDaemon && (!isAbsolutePath(out->mountPoint.c_str()) ||
(!isAbsolutePath( out->mountPoint.c_str() ) || !isAbsolutePath(out->opts->rootDir.c_str()))) {
!isAbsolutePath( out->opts->rootDir.c_str() ) )
)
{
cerr << cerr <<
// xgroup(usage) // xgroup(usage)
_("When specifying daemon mode, you must use absolute paths " _("When specifying daemon mode, you must use absolute paths "
"(beginning with '/')") "(beginning with '/')") << endl;
<< endl;
return false; return false;
} }
// the raw directory may not be a subdirectory of the mount point. // the raw directory may not be a subdirectory of the mount point.
{ {
string testMountPoint = slashTerminate(out->mountPoint); string testMountPoint = slashTerminate(out->mountPoint);
string testRootDir = string testRootDir = out->opts->rootDir.substr(0, testMountPoint.length());
out->opts->rootDir.substr(0, testMountPoint.length());
if( testMountPoint == testRootDir ) if (testMountPoint == testRootDir) {
{
cerr << cerr <<
// xgroup(usage) // xgroup(usage)
_("The raw directory may not be a subdirectory of the " _("The raw directory may not be a subdirectory of the "
@ -408,36 +384,30 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
} }
} }
if(out->opts->delayMount && ! out->opts->mountOnDemand) if (out->opts->delayMount && !out->opts->mountOnDemand) {
{
cerr << cerr <<
// xgroup(usage) // xgroup(usage)
_("You must use mount-on-demand with delay-mount") _("You must use mount-on-demand with delay-mount") << endl;
<< endl;
return false; return false;
} }
if(out->opts->mountOnDemand && out->opts->passwordProgram.empty()) if (out->opts->mountOnDemand && out->opts->passwordProgram.empty()) {
{
cerr << cerr <<
// xgroup(usage) // xgroup(usage)
_("Must set password program when using mount-on-demand") _("Must set password program when using mount-on-demand") << endl;
<< endl;
return false; return false;
} }
// check that the directories exist, or that we can create them.. // check that the directories exist, or that we can create them..
if (!isDirectory(out->opts->rootDir.c_str()) && if (!isDirectory(out->opts->rootDir.c_str()) &&
!userAllowMkdir( out->opts->annotate? 1:0, !userAllowMkdir(out->opts->annotate ? 1 : 0, out->opts->rootDir.c_str(),
out->opts->rootDir.c_str() ,0700)) 0700)) {
{
rWarning(_("Unable to locate root directory, aborting.")); rWarning(_("Unable to locate root directory, aborting."));
return false; return false;
} }
if (!isDirectory(out->mountPoint.c_str()) && if (!isDirectory(out->mountPoint.c_str()) &&
!userAllowMkdir( out->opts->annotate? 2:0, !userAllowMkdir(out->opts->annotate ? 2 : 0, out->mountPoint.c_str(),
out->mountPoint.c_str(),0700)) 0700)) {
{
rWarning(_("Unable to locate mount point, aborting.")); rWarning(_("Unable to locate mount point, aborting."));
return false; return false;
} }
@ -450,8 +420,7 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
static void *idleMonitor(void *); static void *idleMonitor(void *);
void *encfs_init(fuse_conn_info *conn) void *encfs_init(fuse_conn_info *conn) {
{
EncFS_Context *ctx = (EncFS_Context *)fuse_get_context()->private_data; EncFS_Context *ctx = (EncFS_Context *)fuse_get_context()->private_data;
// set fuse connection options // set fuse connection options
@ -459,22 +428,20 @@ void *encfs_init(fuse_conn_info *conn)
// if an idle timeout is specified, then setup a thread to monitor the // if an idle timeout is specified, then setup a thread to monitor the
// filesystem. // filesystem.
if(ctx->args->idleTimeout > 0) if (ctx->args->idleTimeout > 0) {
{
rDebug("starting idle monitoring thread"); rDebug("starting idle monitoring thread");
ctx->running = true; ctx->running = true;
int res = pthread_create( &ctx->monitorThread, 0, idleMonitor, int res = pthread_create(&ctx->monitorThread, 0, idleMonitor, (void *)ctx);
(void*)ctx ); if (res != 0) {
if(res != 0) rError(
{ "error starting idle monitor thread, "
rError("error starting idle monitor thread, " "res = %i, errno = %i",
"res = %i, errno = %i", res, errno); res, errno);
} }
} }
if(ctx->args->isDaemon && oldStderr >= 0) if (ctx->args->isDaemon && oldStderr >= 0) {
{
rInfo("Closing stderr"); rInfo("Closing stderr");
close(oldStderr); close(oldStderr);
oldStderr = -1; oldStderr = -1;
@ -483,11 +450,9 @@ void *encfs_init(fuse_conn_info *conn)
return (void *)ctx; return (void *)ctx;
} }
void encfs_destroy( void *_ctx ) void encfs_destroy(void *_ctx) {
{
EncFS_Context *ctx = (EncFS_Context *)_ctx; EncFS_Context *ctx = (EncFS_Context *)_ctx;
if(ctx->args->idleTimeout > 0) if (ctx->args->idleTimeout > 0) {
{
ctx->running = false; ctx->running = false;
// wake up the thread if it is waiting.. // wake up the thread if it is waiting..
@ -501,8 +466,7 @@ void encfs_destroy( void *_ctx )
} }
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[]) {
{
// initialize the logging library // initialize the logging library
RLogInit(argc, argv); RLogInit(argc, argv);
@ -526,14 +490,12 @@ int main(int argc, char *argv[])
for (int i = 0; i < MaxFuseArgs; ++i) for (int i = 0; i < MaxFuseArgs; ++i)
encfsArgs->fuseArgv[i] = NULL; // libfuse expects null args.. encfsArgs->fuseArgv[i] = NULL; // libfuse expects null args..
if(argc == 1 || !processArgs(argc, argv, encfsArgs)) if (argc == 1 || !processArgs(argc, argv, encfsArgs)) {
{
usage(argv[0]); usage(argv[0]);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if(encfsArgs->isVerbose) if (encfsArgs->isVerbose) {
{
// subscribe to more logging channels.. // subscribe to more logging channels..
slog->subscribeTo(GetGlobalChannel("info")); slog->subscribeTo(GetGlobalChannel("info"));
slog->subscribeTo(GetGlobalChannel("debug")); slog->subscribeTo(GetGlobalChannel("debug"));
@ -611,8 +573,7 @@ int main(int argc, char *argv[])
int returnCode = EXIT_FAILURE; int returnCode = EXIT_FAILURE;
if( rootInfo ) if (rootInfo) {
{
// turn off delayMount, as our prior call to initFS has already // turn off delayMount, as our prior call to initFS has already
// respected any delay, and we want future calls to actually // respected any delay, and we want future calls to actually
// mount. // mount.
@ -623,8 +584,7 @@ int main(int argc, char *argv[])
ctx->args = encfsArgs; ctx->args = encfsArgs;
ctx->opts = encfsArgs->opts; ctx->opts = encfsArgs->opts;
if(encfsArgs->isThreaded == false && encfsArgs->idleTimeout > 0) if (encfsArgs->isThreaded == false && encfsArgs->idleTimeout > 0) {
{
// xgroup(usage) // xgroup(usage)
cerr << _("Note: requested single-threaded mode, but an idle\n" cerr << _("Note: requested single-threaded mode, but an idle\n"
"timeout was specified. The filesystem will operate\n" "timeout was specified. The filesystem will operate\n"
@ -636,8 +596,7 @@ int main(int argc, char *argv[])
// pass-thru calls.. // pass-thru calls..
umask(0); umask(0);
if(encfsArgs->isDaemon) if (encfsArgs->isDaemon) {
{
// switch to logging just warning and error messages via syslog // switch to logging just warning and error messages via syslog
logNode.reset(new SyslogNode("encfs")); logNode.reset(new SyslogNode("encfs"));
logNode->subscribeTo(GetGlobalChannel("warning")); logNode->subscribeTo(GetGlobalChannel("warning"));
@ -651,12 +610,10 @@ int main(int argc, char *argv[])
oldStderr = dup(STDERR_FILENO); oldStderr = dup(STDERR_FILENO);
} }
try try {
{
time_t startTime, endTime; time_t startTime, endTime;
if (encfsArgs->opts->annotate) if (encfsArgs->opts->annotate) cerr << "$STATUS$ fuse_main_start" << endl;
cerr << "$STATUS$ fuse_main_start" << endl;
// FIXME: workaround for fuse_main returning an error on normal // FIXME: workaround for fuse_main returning an error on normal
// exit. Only print information if fuse_main returned // exit. Only print information if fuse_main returned
@ -665,20 +622,17 @@ int main(int argc, char *argv[])
// fuse_main returns an error code in newer versions of fuse.. // fuse_main returns an error code in newer versions of fuse..
int res = fuse_main(encfsArgs->fuseArgc, int res = fuse_main(encfsArgs->fuseArgc,
const_cast<char**>(encfsArgs->fuseArgv), const_cast<char **>(encfsArgs->fuseArgv), &encfs_oper,
&encfs_oper, (void*)ctx); (void *)ctx);
time(&endTime); time(&endTime);
if (encfsArgs->opts->annotate) if (encfsArgs->opts->annotate) cerr << "$STATUS$ fuse_main_end" << endl;
cerr << "$STATUS$ fuse_main_end" << endl;
if(res == 0) if (res == 0) returnCode = EXIT_SUCCESS;
returnCode = EXIT_SUCCESS;
if(res != 0 && encfsArgs->isDaemon && (oldStderr >= 0) if (res != 0 && encfsArgs->isDaemon && (oldStderr >= 0) &&
&& (endTime - startTime <= 1) ) (endTime - startTime <= 1)) {
{
// the users will not have seen any message from fuse, so say a // the users will not have seen any message from fuse, so say a
// few words in libfuse's memory.. // few words in libfuse's memory..
FILE *out = fdopen(oldStderr, "a"); FILE *out = fdopen(oldStderr, "a");
@ -688,12 +642,12 @@ int main(int argc, char *argv[])
" - invalid options -- see usage message\n")); " - invalid options -- see usage message\n"));
fclose(out); fclose(out);
} }
} catch(std::exception &ex) }
{ catch (std::exception &ex) {
rError(_("Internal error: Caught exception from main loop: %s"), rError(_("Internal error: Caught exception from main loop: %s"),
ex.what()); ex.what());
} catch(...) }
{ catch (...) {
rError(_("Internal error: Caught unexpected exception")); rError(_("Internal error: Caught unexpected exception"));
} }
} }
@ -718,9 +672,7 @@ int main(int argc, char *argv[])
const int ActivityCheckInterval = 10; const int ActivityCheckInterval = 10;
static bool unmountFS(EncFS_Context *ctx); static bool unmountFS(EncFS_Context *ctx);
static static void *idleMonitor(void *_arg) {
void * idleMonitor(void *_arg)
{
EncFS_Context *ctx = (EncFS_Context *)_arg; EncFS_Context *ctx = (EncFS_Context *)_arg;
shared_ptr<EncFS_Args> arg = ctx->args; shared_ptr<EncFS_Args> arg = ctx->args;
@ -729,8 +681,7 @@ void * idleMonitor(void *_arg)
pthread_mutex_lock(&ctx->wakeupMutex); pthread_mutex_lock(&ctx->wakeupMutex);
while(ctx->running) while (ctx->running) {
{
int usage = ctx->getAndResetUsageCounter(); int usage = ctx->getAndResetUsageCounter();
if (usage == 0 && ctx->isMounted()) if (usage == 0 && ctx->isMounted())
@ -738,11 +689,9 @@ void * idleMonitor(void *_arg)
else else
idleCycles = 0; idleCycles = 0;
if(idleCycles >= timeoutCycles) if (idleCycles >= timeoutCycles) {
{
int openCount = ctx->openFileCount(); int openCount = ctx->openFileCount();
if( openCount == 0 && unmountFS( ctx ) ) if (openCount == 0 && unmountFS(ctx)) {
{
// wait for main thread to wake us up // wait for main thread to wake us up
pthread_cond_wait(&ctx->wakeupCond, &ctx->wakeupMutex); pthread_cond_wait(&ctx->wakeupCond, &ctx->wakeupMutex);
break; break;
@ -751,16 +700,14 @@ void * idleMonitor(void *_arg)
rDebug("num open files: %i", openCount); rDebug("num open files: %i", openCount);
} }
rDebug("idle cycle count: %i, timeout after %i", idleCycles, rDebug("idle cycle count: %i, timeout after %i", idleCycles, timeoutCycles);
timeoutCycles);
struct timeval currentTime; struct timeval currentTime;
gettimeofday(&currentTime, 0); gettimeofday(&currentTime, 0);
struct timespec wakeupTime; struct timespec wakeupTime;
wakeupTime.tv_sec = currentTime.tv_sec + ActivityCheckInterval; wakeupTime.tv_sec = currentTime.tv_sec + ActivityCheckInterval;
wakeupTime.tv_nsec = currentTime.tv_usec * 1000; wakeupTime.tv_nsec = currentTime.tv_usec * 1000;
pthread_cond_timedwait( &ctx->wakeupCond, pthread_cond_timedwait(&ctx->wakeupCond, &ctx->wakeupMutex, &wakeupTime);
&ctx->wakeupMutex, &wakeupTime );
} }
pthread_mutex_unlock(&ctx->wakeupMutex); pthread_mutex_unlock(&ctx->wakeupMutex);
@ -770,18 +717,15 @@ void * idleMonitor(void *_arg)
return 0; return 0;
} }
static bool unmountFS(EncFS_Context *ctx) static bool unmountFS(EncFS_Context *ctx) {
{
shared_ptr<EncFS_Args> arg = ctx->args; shared_ptr<EncFS_Args> arg = ctx->args;
if( arg->opts->mountOnDemand ) if (arg->opts->mountOnDemand) {
{
rDebug("Detaching filesystem %s due to inactivity", rDebug("Detaching filesystem %s due to inactivity",
arg->mountPoint.c_str()); arg->mountPoint.c_str());
ctx->setRoot(shared_ptr<DirNode>()); ctx->setRoot(shared_ptr<DirNode>());
return false; return false;
} else } else {
{
// Time to unmount! // Time to unmount!
// xgroup(diag) // xgroup(diag)
rWarning(_("Unmounting filesystem %s due to inactivity"), rWarning(_("Unmounting filesystem %s due to inactivity"),
@ -790,4 +734,3 @@ static bool unmountFS(EncFS_Context *ctx)
return true; return true;
} }
} }

View File

@ -31,8 +31,7 @@
using namespace std; using namespace std;
void genKey( const shared_ptr<Cipher> &cipher ) void genKey(const shared_ptr<Cipher> &cipher) {
{
CipherKey key = cipher->newRandomKey(); CipherKey key = cipher->newRandomKey();
// encode with itself // encode with itself
@ -41,13 +40,11 @@ void genKey( const shared_ptr<Cipher> &cipher )
cout << b64Key << "\n"; cout << b64Key << "\n";
} }
int main(int argc, char **argv) int main(int argc, char **argv) {
{
pid_t pid = getpid(); pid_t pid = getpid();
cerr << "pid = " << pid << "\n"; cerr << "pid = " << pid << "\n";
if(argc != 3) if (argc != 3) {
{
cerr << "usage: makeKey [AES|Blowfish] [128|160|192|224|256]\n"; cerr << "usage: makeKey [AES|Blowfish] [128|160|192|224|256]\n";
return 1; return 1;
} }
@ -63,4 +60,3 @@ int main(int argc, char **argv)
// openssl_shutdown(false); // openssl_shutdown(false);
} }

View File

@ -31,39 +31,30 @@
#include <openssl/engine.h> #include <openssl/engine.h>
#endif #endif
unsigned long pthreads_thread_id() unsigned long pthreads_thread_id() { return (unsigned long)pthread_self(); }
{
return (unsigned long)pthread_self();
}
static pthread_mutex_t *crypto_locks = NULL; static pthread_mutex_t *crypto_locks = NULL;
void pthreads_locking_callback( int mode, int n, void pthreads_locking_callback(int mode, int n, const char *caller_file,
const char *caller_file, int caller_line ) int caller_line) {
{
(void)caller_file; (void)caller_file;
(void)caller_line; (void)caller_line;
if(!crypto_locks) if (!crypto_locks) {
{
rDebug("Allocating %i locks for OpenSSL", CRYPTO_num_locks()); rDebug("Allocating %i locks for OpenSSL", CRYPTO_num_locks());
crypto_locks = new pthread_mutex_t[CRYPTO_num_locks()]; crypto_locks = new pthread_mutex_t[CRYPTO_num_locks()];
for (int i = 0; i < CRYPTO_num_locks(); ++i) for (int i = 0; i < CRYPTO_num_locks(); ++i)
pthread_mutex_init(crypto_locks + i, 0); pthread_mutex_init(crypto_locks + i, 0);
} }
if(mode & CRYPTO_LOCK) if (mode & CRYPTO_LOCK) {
{
pthread_mutex_lock(crypto_locks + n); pthread_mutex_lock(crypto_locks + n);
} else } else {
{
pthread_mutex_unlock(crypto_locks + n); pthread_mutex_unlock(crypto_locks + n);
} }
} }
void pthreads_locking_cleanup() void pthreads_locking_cleanup() {
{ if (crypto_locks) {
if(crypto_locks)
{
for (int i = 0; i < CRYPTO_num_locks(); ++i) for (int i = 0; i < CRYPTO_num_locks(); ++i)
pthread_mutex_destroy(crypto_locks + i); pthread_mutex_destroy(crypto_locks + i);
delete[] crypto_locks; delete[] crypto_locks;
@ -71,8 +62,7 @@ void pthreads_locking_cleanup()
} }
} }
void openssl_init(bool threaded) void openssl_init(bool threaded) {
{
// initialize the SSL library // initialize the SSL library
SSL_load_error_strings(); SSL_load_error_strings();
SSL_library_init(); SSL_library_init();
@ -88,8 +78,7 @@ void openssl_init(bool threaded)
ENGINE_register_all_complete(); ENGINE_register_all_complete();
#endif // NO_ENGINE #endif // NO_ENGINE
if(threaded) if (threaded) {
{
// provide locking functions to OpenSSL since we'll be running with // provide locking functions to OpenSSL since we'll be running with
// threads accessing openssl in parallel. // threads accessing openssl in parallel.
CRYPTO_set_id_callback(pthreads_thread_id); CRYPTO_set_id_callback(pthreads_thread_id);
@ -97,13 +86,10 @@ void openssl_init(bool threaded)
} }
} }
void openssl_shutdown(bool threaded) void openssl_shutdown(bool threaded) {
{
#ifndef OPENSSL_NO_ENGINE #ifndef OPENSSL_NO_ENGINE
ENGINE_cleanup(); ENGINE_cleanup();
#endif #endif
if(threaded) if (threaded) pthreads_locking_cleanup();
pthreads_locking_cleanup();
} }

View File

@ -25,5 +25,3 @@ void openssl_init(bool isThreaded);
void openssl_shutdown(bool isThreaded); void openssl_shutdown(bool isThreaded);
#endif #endif

View File

@ -1,4 +1,5 @@
/* $OpenBSD: readpassphrase.c,v 1.12 2001/12/15 05:41:00 millert Exp $ */ /* $OpenBSD: readpassphrase.c,v 1.12 2001/12/15 05:41:00 millert Exp $
*/
/* /*
* Copyright (c) 2000 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 2000 Todd C. Miller <Todd.Miller@courtesan.com>
@ -28,7 +29,8 @@
*/ */
#if defined(LIBC_SCCS) && !defined(lint) #if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$OpenBSD: readpassphrase.c,v 1.12 2001/12/15 05:41:00 millert Exp $"; static const char rcsid[] =
"$OpenBSD: readpassphrase.c,v 1.12 2001/12/15 05:41:00 millert Exp $";
#endif /* LIBC_SCCS and not lint */ #endif /* LIBC_SCCS and not lint */
//#include "includes.h" //#include "includes.h"
@ -64,9 +66,7 @@ static volatile sig_atomic_t signo;
static void handler(int); static void handler(int);
char * char *readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) {
readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
{
ssize_t nr; ssize_t nr;
int input, output, save_errno; int input, output, save_errno;
char ch, *p, *end; char ch, *p, *end;
@ -113,8 +113,7 @@ restart:
/* Turn off echo if possible. */ /* Turn off echo if possible. */
if (tcgetattr(input, &oterm) == 0) { if (tcgetattr(input, &oterm) == 0) {
memcpy(&term, &oterm, sizeof(term)); memcpy(&term, &oterm, sizeof(term));
if (!(flags & RPP_ECHO_ON)) if (!(flags & RPP_ECHO_ON)) term.c_lflag &= ~(ECHO | ECHONL);
term.c_lflag &= ~(ECHO | ECHONL);
#ifdef VSTATUS #ifdef VSTATUS
if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
term.c_cc[VSTATUS] = _POSIX_VDISABLE; term.c_cc[VSTATUS] = _POSIX_VDISABLE;
@ -129,21 +128,17 @@ restart:
end = buf + bufsiz - 1; end = buf + bufsiz - 1;
for (p = buf; (nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r';) { for (p = buf; (nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r';) {
if (p < end) { if (p < end) {
if ((flags & RPP_SEVENBIT)) if ((flags & RPP_SEVENBIT)) ch &= 0x7f;
ch &= 0x7f;
if (isalpha(ch)) { if (isalpha(ch)) {
if ((flags & RPP_FORCELOWER)) if ((flags & RPP_FORCELOWER)) ch = tolower(ch);
ch = tolower(ch); if ((flags & RPP_FORCEUPPER)) ch = toupper(ch);
if ((flags & RPP_FORCEUPPER))
ch = toupper(ch);
} }
*p++ = ch; *p++ = ch;
} }
} }
*p = '\0'; *p = '\0';
save_errno = errno; save_errno = errno;
if (!(term.c_lflag & ECHO)) if (!(term.c_lflag & ECHO)) (void)write(output, "\n", 1);
(void)write(output, "\n", 1);
/* Restore old terminal settings and signals. */ /* Restore old terminal settings and signals. */
if (memcmp(&term, &oterm, sizeof(term)) != 0) if (memcmp(&term, &oterm, sizeof(term)) != 0)
@ -155,8 +150,7 @@ restart:
(void)sigaction(SIGTSTP, &savetstp, NULL); (void)sigaction(SIGTSTP, &savetstp, NULL);
(void)sigaction(SIGTTIN, &savettin, NULL); (void)sigaction(SIGTTIN, &savettin, NULL);
(void)sigaction(SIGTTOU, &savettou, NULL); (void)sigaction(SIGTTOU, &savettou, NULL);
if (input != STDIN_FILENO) if (input != STDIN_FILENO) (void)close(input);
(void)close(input);
/* /*
* If we were interrupted by a signal, resend it to ourselves * If we were interrupted by a signal, resend it to ourselves
@ -188,8 +182,4 @@ getpass(const char *prompt)
} }
#endif #endif
static void handler(int s) static void handler(int s) { signo = s; }
{
signo = s;
}

View File

@ -47,22 +47,18 @@
#endif #endif
#endif #endif
using namespace std; using namespace std;
using namespace rel; using namespace rel;
using namespace rlog; using namespace rlog;
const int FSBlockSize = 256; const int FSBlockSize = 256;
static static int checkErrorPropogation(const shared_ptr<Cipher> &cipher, int size,
int checkErrorPropogation( const shared_ptr<Cipher> &cipher, int byteToChange, const CipherKey &key) {
int size, int byteToChange, const CipherKey &key )
{
MemBlock orig = MemoryPool::allocate(size); MemBlock orig = MemoryPool::allocate(size);
MemBlock data = MemoryPool::allocate(size); MemBlock data = MemoryPool::allocate(size);
for(int i=0; i<size; ++i) for (int i = 0; i < size; ++i) {
{
unsigned char tmp = rand(); unsigned char tmp = rand();
orig.data[i] = tmp; orig.data[i] = tmp;
data.data[i] = tmp; data.data[i] = tmp;
@ -74,11 +70,9 @@ int checkErrorPropogation( const shared_ptr<Cipher> &cipher,
cipher->blockEncode(data.data, size, 0, key); cipher->blockEncode(data.data, size, 0, key);
// intoduce an error in the encoded data, so we can check error propogation // intoduce an error in the encoded data, so we can check error propogation
if(byteToChange >= 0 && byteToChange < size) if (byteToChange >= 0 && byteToChange < size) {
{
unsigned char previousValue = data.data[byteToChange]; unsigned char previousValue = data.data[byteToChange];
do do {
{
data.data[byteToChange] = rand(); data.data[byteToChange] = rand();
} while (data.data[byteToChange] == previousValue); } while (data.data[byteToChange] == previousValue);
} }
@ -89,10 +83,8 @@ int checkErrorPropogation( const shared_ptr<Cipher> &cipher,
cipher->blockDecode(data.data, size, 0, key); cipher->blockDecode(data.data, size, 0, key);
int numByteErrors = 0; int numByteErrors = 0;
for(int i=0; i<size; ++i) for (int i = 0; i < size; ++i) {
{ if (data.data[i] != orig.data[i]) ++numByteErrors;
if( data.data[i] != orig.data[i] )
++numByteErrors;
} }
MemoryPool::release(data); MemoryPool::release(data);
@ -103,56 +95,32 @@ int checkErrorPropogation( const shared_ptr<Cipher> &cipher,
const char TEST_ROOTDIR[] = "/foo"; const char TEST_ROOTDIR[] = "/foo";
static static bool testNameCoding(DirNode &dirNode, bool verbose) {
bool testNameCoding( DirNode &dirNode, bool verbose )
{
// encrypt a name // encrypt a name
const char *name[] = { const char *name[] = {
"1234567", "1234567", "12345678", "123456789",
"12345678", "123456789ABCDEF", "123456789ABCDEF0", "123456789ABCDEF01",
"123456789", "test-name", "test-name2", "test",
"123456789ABCDEF", "../test", "/foo/bar/blah", "test-name.21",
"123456789ABCDEF0", "test-name.22", "test-name.o", "1.test",
"123456789ABCDEF01", "2.test", "a/b/c/d", "a/c/d/e",
"test-name", "b/c/d/e", "b/a/c/d", NULL};
"test-name2",
"test",
"../test",
"/foo/bar/blah",
"test-name.21",
"test-name.22",
"test-name.o",
"1.test",
"2.test",
"a/b/c/d",
"a/c/d/e",
"b/c/d/e",
"b/a/c/d",
NULL
};
const char **orig = name; const char **orig = name;
while(*orig) while (*orig) {
{ if (verbose) cerr << " coding name \"" << *orig << "\"";
if(verbose)
cerr << " coding name \"" << *orig << "\"";
string encName = dirNode.relativeCipherPath(*orig); string encName = dirNode.relativeCipherPath(*orig);
if(verbose) if (verbose) cerr << " -> \"" << encName.c_str() << "\"";
cerr << " -> \"" << encName.c_str() << "\"";
// decrypt name // decrypt name
string decName = dirNode.plainPath(encName.c_str()); string decName = dirNode.plainPath(encName.c_str());
if(decName == *orig) if (decName == *orig) {
{ if (verbose) cerr << " OK\n";
if(verbose) } else {
cerr << " OK\n"; if (verbose) cerr << " FAILED (got " << decName << ")\n";
} else
{
if(verbose)
cerr << " FAILED (got " << decName << ")\n";
return false; return false;
} }
@ -162,15 +130,13 @@ bool testNameCoding( DirNode &dirNode, bool verbose )
return true; return true;
} }
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) if (verbose) cerr << "Testing key save / restore :";
cerr << "Testing key save / restore :";
{ {
CipherKey encodingKey = cipher->newRandomKey(); CipherKey encodingKey = cipher->newRandomKey();
int encodedKeySize = cipher->encodedKeySize(); int encodedKeySize = cipher->encodedKeySize();
@ -178,27 +144,20 @@ bool runTests(const shared_ptr<Cipher> &cipher, bool verbose)
cipher->writeKey(key, keyBuf, encodingKey); cipher->writeKey(key, keyBuf, encodingKey);
CipherKey key2 = cipher->readKey(keyBuf, encodingKey); CipherKey key2 = cipher->readKey(keyBuf, encodingKey);
if(!key2) if (!key2) {
{ if (verbose) cerr << " FAILED (decode error)\n";
if(verbose)
cerr << " FAILED (decode error)\n";
return false; return false;
} }
if(cipher->compareKey( key, key2 )) if (cipher->compareKey(key, key2)) {
{ if (verbose) cerr << " OK\n";
if(verbose) } else {
cerr << " OK\n"; if (verbose) cerr << " FAILED\n";
} else
{
if(verbose)
cerr << " FAILED\n";
return false; return false;
} }
} }
if(verbose) if (verbose) cerr << "Testing Config interface load / store :";
cerr << "Testing Config interface load / store :";
{ {
CipherKey encodingKey = cipher->newRandomKey(); CipherKey encodingKey = cipher->newRandomKey();
int encodedKeySize = cipher->encodedKeySize(); int encodedKeySize = cipher->encodedKeySize();
@ -236,21 +195,15 @@ bool runTests(const shared_ptr<Cipher> &cipher, bool verbose)
// try decoding key.. // try decoding key..
CipherKey key2 = cipher->readKey(cfg2.getKeyData(), encodingKey); CipherKey key2 = cipher->readKey(cfg2.getKeyData(), encodingKey);
if(!key2) if (!key2) {
{ if (verbose) cerr << " FAILED (decode error)\n";
if(verbose)
cerr << " FAILED (decode error)\n";
return false; return false;
} }
if(cipher->compareKey( key, key2 )) if (cipher->compareKey(key, key2)) {
{ if (verbose) cerr << " OK\n";
if(verbose) } else {
cerr << " OK\n"; if (verbose) cerr << " FAILED\n";
} else
{
if(verbose)
cerr << " FAILED\n";
return false; return false;
} }
} }
@ -268,14 +221,13 @@ bool runTests(const shared_ptr<Cipher> &cipher, bool verbose)
fsCfg->opts->idleTracking = false; fsCfg->opts->idleTracking = false;
fsCfg->config->uniqueIV = false; fsCfg->config->uniqueIV = false;
fsCfg->nameCoding.reset( new StreamNameIO( fsCfg->nameCoding.reset(
StreamNameIO::CurrentInterface(), cipher, key ) ); new StreamNameIO(StreamNameIO::CurrentInterface(), cipher, key));
fsCfg->nameCoding->setChainedNameIV(true); fsCfg->nameCoding->setChainedNameIV(true);
DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg); DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg);
if(!testNameCoding( dirNode, verbose )) if (!testNameCoding(dirNode, verbose)) return false;
return false;
} }
if (verbose) if (verbose)
@ -283,166 +235,135 @@ bool runTests(const shared_ptr<Cipher> &cipher, bool verbose)
{ {
fsCfg->opts->idleTracking = false; fsCfg->opts->idleTracking = false;
fsCfg->config->uniqueIV = false; fsCfg->config->uniqueIV = false;
fsCfg->nameCoding.reset( new BlockNameIO( fsCfg->nameCoding.reset(new BlockNameIO(BlockNameIO::CurrentInterface(),
BlockNameIO::CurrentInterface(), cipher, key, cipher, key,
cipher->cipherBlockSize())); cipher->cipherBlockSize()));
fsCfg->nameCoding->setChainedNameIV(true); fsCfg->nameCoding->setChainedNameIV(true);
DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg); DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg);
if(!testNameCoding( dirNode, verbose )) if (!testNameCoding(dirNode, verbose)) return false;
return false;
} }
if (verbose) if (verbose)
cerr << "Testing name encode/decode (block coding w/ IV chaining, base32)\n"; cerr
<< "Testing name encode/decode (block coding w/ IV chaining, base32)\n";
{ {
fsCfg->opts->idleTracking = false; fsCfg->opts->idleTracking = false;
fsCfg->config->uniqueIV = false; fsCfg->config->uniqueIV = false;
fsCfg->nameCoding.reset( new BlockNameIO( fsCfg->nameCoding.reset(new BlockNameIO(BlockNameIO::CurrentInterface(),
BlockNameIO::CurrentInterface(), cipher, key, cipher, key,
cipher->cipherBlockSize(), true)); cipher->cipherBlockSize(), true));
fsCfg->nameCoding->setChainedNameIV(true); fsCfg->nameCoding->setChainedNameIV(true);
DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg); DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg);
if(!testNameCoding( dirNode, verbose )) if (!testNameCoding(dirNode, verbose)) return false;
return false;
} }
if(!verbose) if (!verbose) {
{
{ {
// test stream mode, this time without IV chaining // test stream mode, this time without IV chaining
fsCfg->nameCoding = fsCfg->nameCoding = shared_ptr<NameIO>(
shared_ptr<NameIO>( new StreamNameIO( new StreamNameIO(StreamNameIO::CurrentInterface(), cipher, key));
StreamNameIO::CurrentInterface(), cipher, key ) );
fsCfg->nameCoding->setChainedNameIV(false); fsCfg->nameCoding->setChainedNameIV(false);
DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg); DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg);
if(!testNameCoding( dirNode, verbose )) if (!testNameCoding(dirNode, verbose)) return false;
return false;
} }
{ {
// test block mode, this time without IV chaining // test block mode, this time without IV chaining
fsCfg->nameCoding = shared_ptr<NameIO>( new BlockNameIO( fsCfg->nameCoding = shared_ptr<NameIO>(
BlockNameIO::CurrentInterface(), cipher, key, new BlockNameIO(BlockNameIO::CurrentInterface(), cipher, key,
cipher->cipherBlockSize())); cipher->cipherBlockSize()));
fsCfg->nameCoding->setChainedNameIV(false); fsCfg->nameCoding->setChainedNameIV(false);
DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg); DirNode dirNode(NULL, TEST_ROOTDIR, fsCfg);
if(!testNameCoding( dirNode, verbose )) if (!testNameCoding(dirNode, verbose)) return false;
return false;
} }
} }
if(verbose) if (verbose) cerr << "Testing block encode/decode on full block - ";
cerr << "Testing block encode/decode on full block - ";
{ {
int numErrors = checkErrorPropogation( cipher, int numErrors = checkErrorPropogation(cipher, FSBlockSize, -1, key);
FSBlockSize, -1, key ); if (numErrors) {
if(numErrors) if (verbose) cerr << " FAILED!\n";
{
if(verbose)
cerr << " FAILED!\n";
return false; return false;
} else } else {
{ if (verbose) cerr << " OK\n";
if(verbose)
cerr << " OK\n";
} }
} }
if(verbose) if (verbose) cerr << "Testing block encode/decode on partial block - ";
cerr << "Testing block encode/decode on partial block - ";
{ {
int numErrors = checkErrorPropogation( cipher, int numErrors = checkErrorPropogation(cipher, FSBlockSize - 1, -1, key);
FSBlockSize-1, -1, key ); if (numErrors) {
if(numErrors) if (verbose) cerr << " FAILED!\n";
{
if(verbose)
cerr << " FAILED!\n";
return false; return false;
} else } else {
{ if (verbose) cerr << " OK\n";
if(verbose)
cerr << " OK\n";
} }
} }
if(verbose) if (verbose) cerr << "Checking error propogation in partial block:\n";
cerr << "Checking error propogation in partial block:\n";
{ {
int minChanges = FSBlockSize - 1; int minChanges = FSBlockSize - 1;
int maxChanges = 0; int maxChanges = 0;
int minAt = 0; int minAt = 0;
int maxAt = 0; int maxAt = 0;
for(int i=0; i<FSBlockSize-1; ++i) for (int i = 0; i < FSBlockSize - 1; ++i) {
{ int numErrors = checkErrorPropogation(cipher, FSBlockSize - 1, i, key);
int numErrors = checkErrorPropogation( cipher,
FSBlockSize-1, i, key );
if(numErrors < minChanges) if (numErrors < minChanges) {
{
minChanges = numErrors; minChanges = numErrors;
minAt = i; minAt = i;
} }
if(numErrors > maxChanges) if (numErrors > maxChanges) {
{
maxChanges = numErrors; maxChanges = numErrors;
maxAt = i; maxAt = i;
} }
} }
if(verbose) if (verbose) {
{
cerr << "modification of 1 byte affected between " << minChanges cerr << "modification of 1 byte affected between " << minChanges
<< " and " << maxChanges << " decoded bytes\n"; << " and " << maxChanges << " decoded bytes\n";
cerr << "minimum change at byte " << minAt cerr << "minimum change at byte " << minAt << " and maximum at byte "
<< " and maximum at byte " << maxAt << "\n"; << maxAt << "\n";
} }
} }
if(verbose) if (verbose) cerr << "Checking error propogation on full block:\n";
cerr << "Checking error propogation on full block:\n";
{ {
int minChanges = FSBlockSize; int minChanges = FSBlockSize;
int maxChanges = 0; int maxChanges = 0;
int minAt = 0; int minAt = 0;
int maxAt = 0; int maxAt = 0;
for(int i=0; i<FSBlockSize; ++i) for (int i = 0; i < FSBlockSize; ++i) {
{ int numErrors = checkErrorPropogation(cipher, FSBlockSize, i, key);
int numErrors = checkErrorPropogation( cipher,
FSBlockSize, i, key );
if(numErrors < minChanges) if (numErrors < minChanges) {
{
minChanges = numErrors; minChanges = numErrors;
minAt = i; minAt = i;
} }
if(numErrors > maxChanges) if (numErrors > maxChanges) {
{
maxChanges = numErrors; maxChanges = numErrors;
maxAt = i; maxAt = i;
} }
} }
if(verbose) if (verbose) {
{
cerr << "modification of 1 byte affected between " << minChanges cerr << "modification of 1 byte affected between " << minChanges
<< " and " << maxChanges << " decoded bytes\n"; << " and " << maxChanges << " decoded bytes\n";
cerr << "minimum change at byte " << minAt cerr << "minimum change at byte " << minAt << " and maximum at byte "
<< " and maximum at byte " << maxAt << "\n"; << maxAt << "\n";
} }
} }
return true; return true;
} }
int main(int argc, char *argv[]) {
int main(int argc, char *argv[])
{
RLogInit(argc, argv); RLogInit(argc, argv);
StdioNode stdLog(STDERR_FILENO); StdioNode stdLog(STDERR_FILENO);
@ -467,17 +388,13 @@ int main(int argc, char *argv[])
srand(time(0)); srand(time(0));
// get a list of the available algorithms // get a list of the available algorithms
std::list<Cipher::CipherAlgorithm> algorithms = std::list<Cipher::CipherAlgorithm> algorithms = Cipher::GetAlgorithmList();
Cipher::GetAlgorithmList();
std::list<Cipher::CipherAlgorithm>::const_iterator it; std::list<Cipher::CipherAlgorithm>::const_iterator it;
cerr << "Supported Crypto interfaces:\n"; cerr << "Supported Crypto interfaces:\n";
for(it = algorithms.begin(); it != algorithms.end(); ++it) for (it = algorithms.begin(); it != algorithms.end(); ++it) {
{ cerr << it->name << " ( " << it->iface.name() << " " << it->iface.current()
cerr << it->name << ":" << it->iface.revision() << ":" << it->iface.age()
<< " ( " << it->iface.name() << " " << " ) : " << it->description << "\n";
<< it->iface.current() << ":"
<< it->iface.revision() << ":"
<< it->iface.age() << " ) : " << it->description << "\n";
cerr << " - key length " << it->keyLength.min() << " to " cerr << " - key length " << it->keyLength.min() << " to "
<< it->keyLength.max() << " , block size " << it->blockSize.min() << it->keyLength.max() << " , block size " << it->blockSize.min()
<< " to " << it->blockSize.max() << "\n"; << " to " << it->blockSize.max() << "\n";
@ -485,29 +402,24 @@ int main(int argc, char *argv[])
cerr << "\n"; cerr << "\n";
cerr << "Testing interfaces\n"; cerr << "Testing interfaces\n";
for(it = algorithms.begin(); it != algorithms.end(); ++it) for (it = algorithms.begin(); it != algorithms.end(); ++it) {
{
int blockSize = it->blockSize.closest(256); int blockSize = it->blockSize.closest(256);
for (int keySize = it->keyLength.min(); keySize <= it->keyLength.max(); for (int keySize = it->keyLength.min(); keySize <= it->keyLength.max();
keySize += it->keyLength.inc()) keySize += it->keyLength.inc()) {
{ cerr << it->name << ", key length " << keySize << ", block size "
cerr << it->name << ", key length " << keySize << blockSize << ": ";
<< ", block size " << blockSize << ": ";
shared_ptr<Cipher> cipher = Cipher::New(it->name, keySize); shared_ptr<Cipher> cipher = Cipher::New(it->name, keySize);
if(!cipher) if (!cipher) {
{
cerr << "FAILED TO CREATE\n"; cerr << "FAILED TO CREATE\n";
} else } else {
{ try {
try
{
if (runTests(cipher, false)) if (runTests(cipher, false))
cerr << "OK\n"; cerr << "OK\n";
else else
cerr << "FAILED\n"; cerr << "FAILED\n";
} catch( rlog::Error &er ) }
{ catch (rlog::Error &er) {
cerr << "Error: " << er.what() << "\n"; cerr << "Error: " << er.what() << "\n";
} }
} }
@ -516,11 +428,9 @@ int main(int argc, char *argv[])
// run one test with verbose output too.. // run one test with verbose output too..
shared_ptr<Cipher> cipher = Cipher::New("AES", 192); shared_ptr<Cipher> cipher = Cipher::New("AES", 192);
if(!cipher) if (!cipher) {
{
cerr << "\nNo AES cipher found, skipping verbose test.\n"; cerr << "\nNo AES cipher found, skipping verbose test.\n";
} else } else {
{
cerr << "\nVerbose output for " << cipher->interface().name() cerr << "\nVerbose output for " << cipher->interface().name()
<< " test, key length " << cipher->keySize() * 8 << ", block size " << " test, key length " << cipher->keySize() * 8 << ", block size "
<< FSBlockSize << ":\n"; << FSBlockSize << ":\n";
@ -532,6 +442,3 @@ int main(int argc, char *argv[])
return 0; return 0;
} }