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

@ -27,95 +27,79 @@
#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);
{ _cache.data = new unsigned char[_blockSize];
rAssert( _blockSize > 1 );
_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;
tmp.offset = req.offset; tmp.offset = req.offset;
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)
result = req.dataLen; // only as much as requested result = req.dataLen; // only as much as requested
memcpy( req.data, _cache.data, result ); memcpy(req.data, _cache.data, result);
} }
return result; return result;
} }
} }
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,31 +110,28 @@ 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;
} }
ssize_t readSize = cacheReadOneBlock( blockReq ); ssize_t readSize = cacheReadOneBlock(blockReq);
if(unlikely(readSize <= partialOffset)) if (unlikely(readSize <= partialOffset))
break; // didn't get enough bytes break; // didn't get enough bytes
int cpySize = min( (size_t)(readSize - partialOffset), size ); int cpySize = min((size_t)(readSize - partialOffset), size);
rAssert(cpySize <= readSize); rAssert(cpySize <= readSize);
// if we read to a temporary buffer, then move the data // if we read to a temporary buffer, then move the data
if(blockReq.data != out) if (blockReq.data != out)
memcpy( out, blockReq.data + partialOffset, cpySize ); memcpy(out, blockReq.data + partialOffset, cpySize);
result += cpySize; result += cpySize;
size -= cpySize; size -= cpySize;
@ -158,20 +139,17 @@ 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,28 +162,24 @@ 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);
} }
// 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..
if(blockNum == lastFileBlock && req.dataLen >= lastBlockSize) if (blockNum == lastFileBlock && req.dataLen >= lastBlockSize)
return cacheWriteOneBlock( req ); return cacheWriteOneBlock(req);
} }
// have to merge data with existing block(s).. // have to merge data with existing block(s)..
@ -218,49 +192,42 @@ 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);
// extend data if necessary.. // extend data if necessary..
if( partialOffset + toCopy > blockReq.dataLen ) if (partialOffset + toCopy > blockReq.dataLen)
blockReq.dataLen = partialOffset + toCopy; blockReq.dataLen = partialOffset + toCopy;
} }
// merge in the data to be written.. // merge in the data to be written..
memcpy( blockReq.data + partialOffset, inPtr, toCopy ); memcpy(blockReq.data + partialOffset, inPtr, toCopy);
} }
// 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,32 +254,28 @@ 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;
req.offset = oldLastBlock * _blockSize; req.offset = oldLastBlock * _blockSize;
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;
cacheWriteOneBlock( req ); cacheWriteOneBlock(req);
} }
} 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;
// 1. extend the first block to full length // 1. extend the first block to full length
@ -328,105 +286,88 @@ 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);
req.dataLen = _blockSize; // expand to full block size req.dataLen = _blockSize; // expand to full block size
cacheWriteOneBlock( req ); cacheWriteOneBlock(req);
++oldLastBlock; ++oldLastBlock;
} }
// 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;
memset( mb.data, 0, req.dataLen ); memset(mb.data, 0, req.dataLen);
cacheWriteOneBlock( req ); cacheWriteOneBlock(req);
} }
} }
// 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);
cacheWriteOneBlock( req ); cacheWriteOneBlock(req);
} }
} }
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..
off_t blockNum = size / _blockSize; off_t blockNum = size / _blockSize;
MemBlock mb = MemoryPool::allocate( _blockSize ); MemBlock mb = MemoryPool::allocate(_blockSize);
IORequest req; IORequest req;
req.offset = blockNum * _blockSize; req.offset = blockNum * _blockSize;
req.dataLen = _blockSize; req.dataLen = _blockSize;
req.data = mb.data; req.data = mb.data;
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,30 +32,28 @@
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();
// implemented in terms of blocks. // implemented in terms of blocks.
virtual ssize_t read( const IORequest &req ) const; virtual ssize_t read(const IORequest &req) const;
virtual bool write( const IORequest &req ); virtual bool write(const IORequest &req);
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 );
// same as read(), except that the request.offset field is guarenteed to be // same as read(), except that the request.offset field is guarenteed to be
// block aligned, and the request size will not be larger then 1 block. // block aligned, and the request size will not be larger then 1 block.
virtual ssize_t readOneBlock( const IORequest &req ) const =0; virtual ssize_t readOneBlock(const IORequest &req) const = 0;
virtual bool writeOneBlock( const IORequest &req ) =0; virtual bool writeOneBlock(const IORequest &req) = 0;
ssize_t cacheReadOneBlock( const IORequest &req ) const; ssize_t cacheReadOneBlock(const IORequest &req) const;
bool cacheWriteOneBlock( const IORequest &req ); bool cacheWriteOneBlock(const IORequest &req);
int _blockSize; int _blockSize;
bool _allowHoles; bool _allowHoles;
@ -65,4 +63,3 @@ protected:
}; };
#endif #endif

View File

@ -33,44 +33,42 @@
using namespace rlog; using namespace rlog;
using namespace rel; 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 shared_ptr<Cipher> &cipher, const CipherKey &key ) 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);
@ -98,171 +95,145 @@ Interface BlockNameIO::CurrentInterface(bool caseSensitive)
return Interface("nameio/block", 4, 0, 2); return Interface("nameio/block", 4, 0, 2);
} }
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;
int encodedNameLen = numBlocks * _bs + 2; // 2 checksum bytes int encodedNameLen = numBlocks * _bs + 2; // 2 checksum bytes
if (_caseSensitive) if (_caseSensitive)
return B256ToB32Bytes( encodedNameLen ); return B256ToB32Bytes(encodedNameLen);
else else
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,
length+padding, _key, iv ); length + padding, _key, iv);
// add checksum bytes // add checksum bytes
encodedName[0] = (mac >> 8) & 0xff; encodedName[0] = (mac >> 8) & 0xff;
encodedName[1] = (mac ) & 0xff; encodedName[1] = (mac) & 0xff;
_cipher->blockEncode( (unsigned char *)encodedName+2, length+padding, _cipher->blockEncode((unsigned char *)encodedName + 2, length + padding,
(uint64_t)mac ^ tmpIV, _key); (uint64_t)mac ^ tmpIV, _key);
// convert to base 64 ascii // convert to base 64 ascii
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);
// find out true string length // find out true string length
int padding = (unsigned char)tmpBuf[2+decodedStreamLen-1]; int padding = (unsigned char)tmpBuf[2 + decodedStreamLen - 1];
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, throw ERROR("invalid padding size");
_bs, finalSize);
throw ERROR( "invalid padding size" );
} }
// copy out the result.. // copy out the result..
memcpy(plaintextName, tmpBuf+2, finalSize); memcpy(plaintextName, tmpBuf + 2, finalSize);
plaintextName[finalSize] = '\0'; plaintextName[finalSize] = '\0';
// check the mac // check the mac
unsigned int mac2 = _cipher->MAC_16((const unsigned char *)tmpBuf+2, unsigned int mac2 = _cipher->MAC_16((const unsigned char *)tmpBuf + 2,
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", finalSize); rDebug("on decode of %i bytes", finalSize);
throw ERROR( "checksum mismatch in filename decode" ); throw ERROR("checksum mismatch in filename decode");
} }
return finalSize; return finalSize;
} }
bool BlockNameIO::Enabled() bool BlockNameIO::Enabled() { return true; }
{
return true;
}

View File

@ -32,31 +32,30 @@ 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();
virtual rel::Interface interface() const; virtual rel::Interface interface() const;
virtual int maxEncodedNameLen( int plaintextNameLen ) const; virtual int maxEncodedNameLen(int plaintextNameLen) const;
virtual int maxDecodedNameLen( int encodedNameLen ) const; virtual int maxDecodedNameLen(int encodedNameLen) const;
// hack to help with static builds // hack to help with static builds
static bool Enabled(); static bool Enabled();
protected:
virtual int encodeName( const char *plaintextName, int length,
uint64_t *iv, char *encodedName ) const;
virtual int decodeName( const char *encodedName, int length,
uint64_t *iv, char *plaintextName ) const;
private: protected:
virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
char *encodedName) const;
virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
char *plaintextName) const;
private:
int _interface; int _interface;
int _bs; int _bs;
shared_ptr<Cipher> _cipher; shared_ptr<Cipher> _cipher;
@ -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;
@ -60,25 +55,21 @@ struct CipherAlg
Range blockSize; Range blockSize;
}; };
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;
@ -86,7 +77,7 @@ Cipher::GetAlgorithmList( bool includeHidden )
tmp.keyLength = it->second.keyLength; tmp.keyLength = it->second.keyLength;
tmp.blockSize = it->second.blockSize; tmp.blockSize = it->second.blockSize;
result.push_back( tmp ); result.push_back(tmp);
} }
} }
@ -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;
@ -118,44 +107,37 @@ bool Cipher::Register(const char *name, const char *description,
ca.keyLength = keyLength; ca.keyLength = keyLength;
ca.blockSize = blockSize; ca.blockSize = blockSize;
gCipherMap->insert( make_pair(string(name), ca) ); gCipherMap->insert(make_pair(string(name), ca));
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);
} }
} }
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);
// if we're not going to compare the options, then just stop // if we're not going to compare the options, then just stop
// now.. // now..
@ -167,28 +149,22 @@ 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);
return mac32; return mac32;
} }
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);
unsigned int mac16 = ((mac32 >> 16) & 0xffff) ^ (mac32 & 0xffff); unsigned int mac16 = ((mac32 >> 16) & 0xffff) ^ (mac32 & 0xffff);
@ -196,33 +172,30 @@ 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];
// write the key, encoding it with itself. // write the key, encoding it with itself.
this->writeKey( key, keyBuf, encodingKey ); this->writeKey(key, keyBuf, encodingKey);
int b64Len = B256ToB64Bytes( encodedKeySize ); int b64Len = B256ToB64Bytes(encodedKeySize);
unsigned char *b64Key = new unsigned char[ b64Len + 1 ]; unsigned char *b64Key = new unsigned char[b64Len + 1];
changeBase2( keyBuf, encodedKeySize, 8, b64Key, b64Len, 6 ); changeBase2(keyBuf, encodedKeySize, 8, b64Key, b64Len, 6);
B64ToAscii( b64Key, b64Len ); B64ToAscii(b64Key, b64Len);
b64Key[ b64Len - 1 ] = '\0'; b64Key[b64Len - 1] = '\0';
return string( (const char *)b64Key ); return string((const char *)b64Key);
} }

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,34 +52,24 @@ 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();
virtual rel::Interface interface() const =0; virtual rel::Interface interface() const = 0;
// create a new key based on a password // create a new key based on a password
// if iterationCount == 0, then iteration count will be determined // if iterationCount == 0, then iteration count will be determined
@ -90,54 +78,55 @@ public:
// milliseconds the password derivation function should take to run. // milliseconds the password derivation function should take to run.
virtual CipherKey newKey(const char *password, int passwdLength, virtual CipherKey newKey(const char *password, int passwdLength,
int &iterationCount, long desiredFunctionDuration, int &iterationCount, long desiredFunctionDuration,
const unsigned char *salt, int saltLen) =0; const unsigned char *salt, int saltLen) = 0;
// deprecated - for backward compatibility // deprecated - for backward compatibility
virtual CipherKey newKey(const char *password, int passwdLength ) =0; virtual CipherKey newKey(const char *password, int passwdLength) = 0;
// create a new random key // create a new random key
virtual CipherKey newRandomKey() =0; virtual CipherKey newRandomKey() = 0;
// data must be len encodedKeySize() // data must be len encodedKeySize()
virtual CipherKey readKey(const unsigned char *data, virtual CipherKey readKey(const unsigned char *data,
const CipherKey &encodingKey, const CipherKey &encodingKey,
bool checkKey = true) =0; bool checkKey = true) = 0;
virtual void writeKey(const CipherKey &key, unsigned char *data, virtual void writeKey(const CipherKey &key, unsigned char *data,
const CipherKey &encodingKey) =0; const CipherKey &encodingKey) = 0;
virtual std::string encodeAsString(const CipherKey &key, virtual std::string encodeAsString(const CipherKey &key,
const CipherKey &encodingKey ); const CipherKey &encodingKey);
// for testing purposes // for testing purposes
virtual bool compareKey( const CipherKey &A, const CipherKey &B ) const =0; virtual bool compareKey(const CipherKey &A, const CipherKey &B) const = 0;
// meta-data about the cypher // meta-data about the cypher
virtual int keySize() const=0; virtual int keySize() const = 0;
virtual int encodedKeySize() const=0; // size virtual int encodedKeySize() const = 0; // size
virtual int cipherBlockSize() const=0; // size of a cipher block virtual int cipherBlockSize() const = 0; // size of a cipher block
// fill the supplied buffer with random data // fill the supplied buffer with random data
// The data may be pseudo random and might not be suitable for key // The data may be pseudo random and might not be suitable for key
// generation. For generating keys, uses newRandomKey() instead. // generation. For generating keys, uses newRandomKey() instead.
// Returns true on success, false on failure. // Returns true on success, false on failure.
virtual bool randomize( unsigned char *buf, int len, virtual bool randomize(unsigned char *buf, int len,
bool strongRandom ) const =0; bool strongRandom) const = 0;
// 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,98 +39,77 @@ 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
return false; return false;
} }
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;
static bool warnOnce = false; static bool warnOnce = false;
if(!warnOnce) if (!warnOnce)
warnOnce = checkSize( fsConfig->config->blockSize, warnOnce = checkSize(fsConfig->config->blockSize,
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,23 +119,20 @@ 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;
} }
} }
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};
@ -192,88 +164,76 @@ void CipherFileIO::initHeader( )
req.offset = 0; req.offset = 0;
req.data = buf; req.data = buf;
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;
req.offset = 0; req.offset = 0;
req.data = buf; req.data = buf;
req.dataLen = 8; req.dataLen = 8;
base->write( req ); base->write(req);
} else } else
rDebug("base not writable, IV not written.."); rDebug("base not writable, IV not written..");
} }
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;
} }
cipher->streamEncode( buf, sizeof(buf), externalIV, key ); cipher->streamEncode(buf, sizeof(buf), externalIV, key);
IORequest req; IORequest req;
req.offset = 0; req.offset = 0;
req.data = buf; req.data = buf;
req.dataLen = 8; req.dataLen = 8;
base->write( req ); base->write(req);
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,110 +266,85 @@ 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
return cipher->blockDecode( buf, size, _iv64, key ); return cipher->blockDecode(buf, size, _iv64, key);
} }
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
return cipher->blockDecode( buf, size, _iv64, key ); return cipher->blockDecode(buf, size, _iv64, key);
} }
} }
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)
rDebug("writeHeader failed to re-open for write"); rDebug("writeHeader failed to re-open for write");
} }
initHeader(); initHeader();
@ -422,16 +352,11 @@ int CipherFileIO::truncate( off_t size )
// can't let BlockFileIO call base->truncate(), since it would be using // can't let BlockFileIO call base->truncate(), since it would be using
// 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,42 +34,36 @@ 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, const FSConfigPtr &cfg);
CipherFileIO( const shared_ptr<FileIO> &base,
const FSConfigPtr &cfg);
virtual ~CipherFileIO(); virtual ~CipherFileIO();
virtual rel::Interface interface() const; virtual rel::Interface interface() const;
virtual void setFileName( const char *fileName ); virtual void setFileName(const char *fileName);
virtual const char *getFileName() const; virtual const char *getFileName() const;
virtual bool setIV( uint64_t iv ); virtual bool setIV(uint64_t iv);
virtual int open( int flags ); virtual int open(int flags);
virtual int getAttr( struct stat *stbuf ) const; virtual int getAttr(struct stat *stbuf) const;
virtual off_t getSize() const; virtual off_t getSize() const;
virtual int truncate( off_t size ); virtual int truncate(off_t size);
virtual bool isWritable() const; virtual bool isWritable() const;
private: private:
virtual ssize_t readOneBlock( const IORequest &req ) const; virtual ssize_t readOneBlock(const IORequest &req) const;
virtual bool writeOneBlock( const IORequest &req ); virtual bool writeOneBlock(const IORequest &req);
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,9 +23,8 @@
#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,98 +28,78 @@
#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;
} }
ConfigVar in; ConfigVar in;
in.write( (unsigned char *)buf, size ); in.write((unsigned char *)buf, size);
delete[] buf; delete[] buf;
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;
} }
ConfigVar newVar( value ); ConfigVar newVar(value);
vars.insert( make_pair( key, newVar ) ); vars.insert(make_pair(key, newVar));
} }
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,36 +107,30 @@ 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() ); out.write((unsigned char *)it->second.buffer(), it->second.size());
out.write( (unsigned char*)it->second.buffer(), it->second.size() );
} }
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())
return ConfigVar(); return ConfigVar();
else else
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,9 +43,8 @@
ConfigReader cfg; ConfigReader cfg;
cfg["cipher"] << cipher->interface(); cfg["cipher"] << cipher->interface();
*/ */
class ConfigReader class ConfigReader {
{ public:
public:
ConfigReader(); ConfigReader();
~ConfigReader(); ~ConfigReader();
@ -53,14 +52,13 @@ public:
bool save(const char *fileName) const; bool save(const char *fileName) const;
ConfigVar toVar() const; ConfigVar toVar() const;
bool loadFromVar( ConfigVar &var ); bool loadFromVar(ConfigVar &var);
ConfigVar operator[](const std::string &varName) const; ConfigVar operator[](const std::string &varName) const;
ConfigVar &operator[](const std::string &varName); ConfigVar &operator[](const std::string &varName);
private: private:
std::map<std::string, ConfigVar> vars; std::map<std::string, ConfigVar> vars;
}; };
#endif #endif

View File

@ -26,39 +26,22 @@
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
pd = src.pd; pd = src.pd;
@ -66,31 +49,23 @@ 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);
{ } else {
pd->buffer.append( (const char *)data, bytes ); pd->buffer.insert(pd->offset, (const char *)data, bytes);
} else
{
pd->buffer.insert( pd->offset, (const char *)data, bytes );
} }
pd->offset += bytes; pd->offset += 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,112 +104,97 @@ 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();
int value = 0; int value = 0;
bool highBitSet; bool highBitSet;
rAssert( offset < bytes ); rAssert(offset < bytes);
do do {
{
unsigned char tmp = buf[offset++]; unsigned char tmp = buf[offset++];
highBitSet = tmp & 0x80; highBitSet = tmp & 0x80;
value = (value << 7) | (int)(tmp & 0x7f); value = (value << 7) | (int)(tmp & 0x7f);
} while(highBitSet && offset < bytes); } while (highBitSet && offset < bytes);
pd->offset = offset; pd->offset = offset;
// should never end up with a negative number.. // should never end up with a negative number..
rAssert( value >= 0 ); rAssert(value >= 0);
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();
if(offset >= bytes) if (offset >= bytes)
return defaultValue; return defaultValue;
else else
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,23 +24,21 @@
#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;
}; };
shared_ptr<ConfigVarData> pd; shared_ptr<ConfigVarData> pd;
public: public:
ConfigVar(); ConfigVar();
ConfigVar(const std::string &buffer); ConfigVar(const std::string &buffer);
ConfigVar(const ConfigVar &src); ConfigVar(const ConfigVar &src);
~ConfigVar(); ~ConfigVar();
ConfigVar & operator = (const ConfigVar &src); ConfigVar &operator=(const ConfigVar &src);
// reset read/write offset.. // reset read/write offset..
void resetOffset(); void resetOffset();
@ -52,10 +50,10 @@ public:
int write(const unsigned char *data, int size); int write(const unsigned char *data, int size);
int readInt() const; int readInt() const;
int readInt( int defaultValue ) const; int readInt(int defaultValue) const;
void writeInt(int value); void writeInt(int value);
bool readBool( bool defaultValue ) const; bool readBool(bool defaultValue) const;
void writeString(const char *data, int size); void writeString(const char *data, int size);
@ -69,13 +67,12 @@ public:
int at() const; int at() const;
}; };
ConfigVar & operator << (ConfigVar &, bool); ConfigVar &operator<<(ConfigVar &, bool);
ConfigVar & operator << (ConfigVar &, int); ConfigVar &operator<<(ConfigVar &, int);
ConfigVar & operator << (ConfigVar &, const std::string &str); ConfigVar &operator<<(ConfigVar &, const std::string &str);
const ConfigVar & operator >> (const ConfigVar &, bool &); const ConfigVar &operator>>(const ConfigVar &, bool &);
const ConfigVar & operator >> (const ConfigVar &, int &); 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,67 +29,55 @@
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 );
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 );
// release all entries from map // release all entries from map
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;
} }
} }
} while(!ret); } while (!ret);
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;
usageCount = 0; usageCount = 0;
@ -97,81 +85,70 @@ 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);
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;
FileMap::iterator it = openFiles.find( std::string(path) ); FileMap::iterator it = openFiles.find(std::string(path));
rAssert(it != openFiles.end()); rAssert(it != openFiles.end());
int rmCount = it->second.erase( ph ); int rmCount = it->second.erase(ph);
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;
openFiles.erase( it ); openFiles.erase(it);
storedName.assign( storedName.length(), '\0' ); storedName.assign(storedName.length(), '\0');
} }
delete ph; delete ph;
} }

View File

@ -37,9 +37,8 @@ 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();
@ -72,7 +71,7 @@ public:
pthread_cond_t wakeupCond; pthread_cond_t wakeupCond;
pthread_mutex_t wakeupMutex; pthread_mutex_t wakeupMutex;
private: private:
/* This placeholder is what is referenced in FUSE context (passed to /* This placeholder is what is referenced in FUSE context (passed to
* callbacks). * callbacks).
* *
@ -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;
@ -105,7 +101,6 @@ private:
shared_ptr<DirNode> root; shared_ptr<DirNode> root;
}; };
int remountFS( EncFS_Context *ctx ); int remountFS(EncFS_Context *ctx);
#endif #endif

View File

@ -48,35 +48,21 @@ using namespace std;
using namespace rel; using namespace rel;
using namespace rlog; 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) { ::closedir(d); }
void operator () ( DIR *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;
{ while (_nextName(de, dir, fileType, inode)) {
struct dirent *de=0; try {
while(_nextName(de, dir, fileType, inode))
{
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,28 +113,24 @@ 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);
} }
} }
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,83 +142,63 @@ 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;
list<RenameEl>::const_iterator last; list<RenameEl>::const_iterator last;
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,21 +229,18 @@ 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...
} }
++undoCount; ++undoCount;
@ -304,13 +249,11 @@ 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);
ctx = _ctx; ctx = _ctx;
rootDir = sourceDir; rootDir = sourceDir;
@ -318,180 +261,143 @@ 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 return naming->decodePath(cipherPath_ + rootDir.length());
{ } else {
if( !strncmp( cipherPath_, rootDir.c_str(), if (cipherPath_[0] == '+') {
rootDir.length() ) )
{
return naming->decodePath( cipherPath_ + rootDir.length() );
} else
{
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);
return string(); return string();
} }
} }
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);
return string(); return string();
} }
} }
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 )
{
rError("encode err: %s", err.message());
err.log( _RLWarningChannel );
} }
return DirTraverse( dp, iv, naming ); catch (rlog::Error &err) {
rError("encode err: %s", err.message());
err.log(_RLWarningChannel);
}
return DirTraverse(dp, iv, naming);
} }
} }
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
string fromCPart = naming->encodePath( fromP, &fromIV ); string fromCPart = naming->encodePath(fromP, &fromIV);
string toCPart = naming->encodePath( toP, &toIV ); string toCPart = naming->encodePath(toP, &toIV);
// where the files live before the rename.. // where the files live before the rename..
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);
// store rename information.. // store rename information..
string oldFull = sourcePath + '/' + de->d_name; string oldFull = sourcePath + '/' + de->d_name;
@ -505,41 +411,35 @@ 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
{ {
isDir = isDirectory( oldFull.c_str() ); isDir = isDirectory(oldFull.c_str());
} }
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",
fromCPart.append(1, '/').append(de->d_name).c_str()); fromCPart.append(1, '/').append(de->d_name).c_str());
err.log( _RLDebugChannel ); err.log(_RLDebugChannel);
// abort.. Err on the side of safety and disallow rename, rather // abort.. Err on the side of safety and disallow rename, rather
// then loosing files.. // then loosing files..
@ -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,49 +458,39 @@ 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,
gid_t gid) {
string cyName = rootDir + naming->encodePath(plaintextPath);
rAssert(!cyName.empty());
int DirNode::mkdir(const char *plaintextPath, mode_t mode, rLog(Info, "mkdir on %s", cyName.c_str());
uid_t uid, gid_t gid)
{
string cyName = rootDir + naming->encodePath( plaintextPath );
rAssert( !cyName.empty() );
rLog( Info, "mkdir on %s", cyName.c_str() );
// 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,97 +498,84 @@ 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);
string toCName = rootDir + naming->encodePath( toPlaintext ); string toCName = rootDir + naming->encodePath(toPlaintext);
rAssert( !fromCName.empty() ); rAssert(!fromCName.empty());
rAssert( !toCName.empty() ); rAssert(!toCName.empty());
rLog( Info, "rename %s -> %s", fromCName.c_str(), toCName.c_str() ); rLog(Info, "rename %s -> %s", fromCName.c_str(), toCName.c_str());
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;
} }
rLog( Info, "recursive rename end" ); rLog(Info, "recursive rename end");
} }
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;
} }
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);
string toCName = rootDir + naming->encodePath( to ); string toCName = rootDir + naming->encodePath(to);
rAssert( !fromCName.empty() ); rAssert(!fromCName.empty());
rAssert( !toCName.empty() ); rAssert(!toCName.empty());
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;
else else
res = 0; res = 0;
@ -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,13 +633,12 @@ 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);
shared_ptr<FileNode> node = findOrCreate( plainName ); shared_ptr<FileNode> node = findOrCreate(plainName);
return node; return node;
} }
@ -784,44 +648,41 @@ 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);
shared_ptr<FileNode> node = findOrCreate( plainName ); shared_ptr<FileNode> node = findOrCreate(plainName);
if( node && (*result = node->open( flags )) >= 0 ) if (node && (*result = node->open(flags)) >= 0)
return node; return node;
else else
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,15 +40,14 @@ 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);
DirTraverse(const DirTraverse &src); DirTraverse(const DirTraverse &src);
~DirTraverse(); ~DirTraverse();
DirTraverse &operator = (const DirTraverse &src); DirTraverse &operator=(const DirTraverse &src);
// returns FALSE to indicate an invalid DirTraverse (such as when // returns FALSE to indicate an invalid DirTraverse (such as when
// an invalid directory is requested for traversal) // an invalid directory is requested for traversal)
@ -57,14 +56,14 @@ public:
// return next plaintext filename // return next plaintext filename
// If fileType is not 0, then it is used to return the filetype (or 0 if // If fileType is not 0, then it is used to return the filetype (or 0 if
// unknown) // unknown)
std::string nextPlaintextName(int *fileType=0, ino_t *inode=0); std::string nextPlaintextName(int *fileType = 0, ino_t *inode = 0);
/* Return cipher name of next undecodable filename.. /* Return cipher name of next undecodable filename..
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,49 +73,46 @@ 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();
// return the path to the root directory // return the path to the root directory
std::string rootDirectory(); std::string rootDirectory();
// find files // find files
shared_ptr<FileNode> lookupNode( const char *plaintextName, shared_ptr<FileNode> lookupNode(const char *plaintextName,
const char *requestor ); const char *requestor);
/* /*
Combined lookupNode + node->open() call. If the open fails, then the Combined lookupNode + node->open() call. If the open fails, then the
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);
std::string plainPath( const char *cipherPath ); std::string plainPath(const char *cipherPath);
// relative cipherPath is the same as cipherPath except that it doesn't // relative cipherPath is the same as cipherPath except that it doesn't
// prepent the mount point. That it, it doesn't return a fully qualified // prepent the mount point. That it, it doesn't return a fully qualified
// name, just a relative path within the encrypted filesystem. // name, just a relative path within the encrypted filesystem.
std::string relativeCipherPath( const char *plaintextPath ); std::string relativeCipherPath(const char *plaintextPath);
/* /*
Returns true if file names are dependent on the parent directory name. Returns true if file names are dependent on the parent directory name.
@ -126,33 +122,32 @@ public:
bool hasDirectoryNameDependency() const; bool hasDirectoryNameDependency() const;
// unlink the specified file // unlink the specified file
int unlink( const char *plaintextName ); int unlink(const char *plaintextName);
// traverse directory // traverse directory
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);
int link( const char *from, const char *to ); int link(const char *from, const char *to);
// returns idle time of filesystem in seconds // returns idle time of filesystem in seconds
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
this call has no effect. this call has no effect.
Returns the FileNode if it was found. Returns the FileNode if it was found.
*/ */
shared_ptr<FileNode> renameNode( const char *from, const char *to ); shared_ptr<FileNode> renameNode(const char *from, const char *to);
shared_ptr<FileNode> renameNode( const char *from, const char *to, shared_ptr<FileNode> renameNode(const char *from, const char *to,
bool forwardMode ); bool forwardMode);
/* /*
when directory IV chaining is enabled, a directory can't be renamed when directory IV chaining is enabled, a directory can't be renamed
@ -160,16 +155,15 @@ protected:
called after renaming the directory, passing in the plaintext from and called after renaming the directory, passing in the plaintext from and
to paths. to paths.
*/ */
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,
const char *toP ); const char *toP);
shared_ptr<FileNode> findOrCreate( const char *plainName); shared_ptr<FileNode> findOrCreate(const char *plainName);
pthread_mutex_t mutex; pthread_mutex_t mutex;

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;
@ -103,16 +98,15 @@ struct EncFSConfig
unsigned char *getKeyData() const; unsigned char *getKeyData() const;
unsigned char *getSaltData() const; unsigned char *getSaltData() const;
private: private:
CipherKey makeKey(const char *password, int passwdLen); CipherKey makeKey(const char *password, int passwdLen);
}; };
// helpers for serializing to/from a stream // helpers for serializing to/from a stream
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,50 +37,44 @@ 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();
virtual rel::Interface interface() const =0; virtual rel::Interface interface() const = 0;
// default implementation returns 1, meaning this is not block oriented. // default implementation returns 1, meaning this is not block oriented.
virtual int blockSize() const; virtual int blockSize() const;
virtual void setFileName(const char *fileName) =0; virtual void setFileName(const char *fileName) = 0;
virtual const char *getFileName() const =0; virtual const char *getFileName() const = 0;
// Not sure about this -- it is specific to CipherFileIO, but the // Not sure about this -- it is specific to CipherFileIO, but the
// alternative methods of exposing this interface aren't much nicer.. // alternative methods of exposing this interface aren't much nicer..
virtual bool setIV( uint64_t iv ); virtual bool setIV(uint64_t iv);
// open file for specified mode. There is no corresponding close, so a // open file for specified mode. There is no corresponding close, so a
// file is open until the FileIO interface is destroyed. // file is open until the FileIO interface is destroyed.
virtual int open( int flags ) =0; virtual int open(int flags) = 0;
// get filesystem attributes for a file // get filesystem attributes for a file
virtual int getAttr( struct stat *stbuf ) const =0; virtual int getAttr(struct stat *stbuf) const = 0;
virtual off_t getSize( ) const =0; virtual off_t getSize() const = 0;
virtual ssize_t read( const IORequest &req ) const =0; virtual ssize_t read(const IORequest &req) const = 0;
virtual bool write( const IORequest &req ) =0; virtual bool write(const IORequest &req) = 0;
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 &);
FileIO &operator = ( const FileIO & ); FileIO &operator=(const FileIO &);
}; };
#endif #endif

View File

@ -66,11 +66,10 @@ 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);
this->_pname = plaintextName_; this->_pname = plaintextName_;
this->_cname = cipherName_; this->_cname = cipherName_;
@ -79,82 +78,62 @@ FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg,
this->fsConfig = cfg; this->fsConfig = cfg;
// chain RawFileIO & CipherFileIO // chain RawFileIO & CipherFileIO
shared_ptr<FileIO> rawIO( new RawFileIO( _cname ) ); shared_ptr<FileIO> rawIO(new RawFileIO(_cname));
io = shared_ptr<FileIO>( new CipherFileIO( rawIO, fsConfig )); io = shared_ptr<FileIO>(new CipherFileIO(rawIO, fsConfig));
if(cfg->config->blockMACBytes || cfg->config->blockMACRandBytes) if (cfg->config->blockMACBytes || cfg->config->blockMACRandBytes)
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 );
_pname.assign( _pname.length(), '\0' ); _pname.assign(_pname.length(), '\0');
_cname.assign( _cname.length(), '\0' ); _cname.assign(_cname.length(), '\0');
io.reset(); io.reset();
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);
else else
return true; return true;
} }
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;
} }
@ -195,22 +169,18 @@ int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid)
* The regular file stuff could be stripped off if there * The regular file stuff could be stripped off if there
* were a create method (advised to have) * were a create method (advised to have)
*/ */
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,77 +189,69 @@ 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;
req.data = data; req.data = data;
Lock _lock( mutex ); Lock _lock(mutex);
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;
req.dataLen = size; req.dataLen = size;
req.data = data; req.data = data;
Lock _lock( mutex ); Lock _lock(mutex);
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)
res = fdatasync( fh ); res = fdatasync(fh);
else else
res = fsync( fh ); res = fsync(fh);
#else #else
(void)datasync; (void)datasync;
// no fdatasync support // no fdatasync support
@ -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, const FSConfigPtr &cfg, const char *plaintextName,
FileNode(DirNode *parent,
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
@ -68,12 +65,12 @@ public:
bool write(off_t offset, unsigned char *data, ssize_t size); bool write(off_t offset, unsigned char *data, ssize_t size);
// truncate the file to a particular size // truncate the file to a particular size
int truncate( off_t size ); int truncate(off_t size);
// 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
@ -89,12 +86,9 @@ private:
std::string _cname; // encrypted name std::string _cname; // encrypted name
DirNode *parent; DirNode *parent;
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

@ -27,26 +27,25 @@
#include "FSConfig.h" #include "FSConfig.h"
// true if the path points to an existing node (of any type) // true if the path points to an existing node (of any type)
bool fileExists( const char *fileName ); bool fileExists(const char *fileName);
// true if path is a directory // true if path is a directory
bool isDirectory( const char *fileName ); bool isDirectory(const char *fileName);
// true if starts with '/' // true if starts with '/'
bool isAbsolutePath( const char *fileName ); bool isAbsolutePath(const char *fileName);
// pointer to just after the last '/' // pointer to just after the last '/'
const char *lastPathElement( const char *name ); const char *lastPathElement(const char *name);
std::string parentDirectory( const std::string &path ); std::string parentDirectory(const std::string &path);
// ask the user for permission to create the directory. If they say ok, then // ask the user for permission to create the directory. If they say ok, then
// do it and return true. // do it and return true.
bool userAllowMkdir(const char *dirPath, mode_t mode ); bool userAllowMkdir(const char *dirPath, mode_t mode);
bool userAllowMkdir(int promptno, const char *dirPath, mode_t mode ); 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;
@ -104,41 +96,37 @@ struct EncFS_Opts
/* /*
Read existing config file. Looks for any supported configuration version. Read existing config file. Looks for any supported configuration version.
*/ */
ConfigType readConfig( const std::string &rootDir, ConfigType readConfig(const std::string &rootDir,
const shared_ptr<EncFSConfig> &config ); const shared_ptr<EncFSConfig> &config);
/* /*
Save the configuration. Saves back as the same configuration type as was Save the configuration. Saves back as the same configuration type as was
read from. read from.
*/ */
bool saveConfig( ConfigType type, const std::string &rootdir, bool saveConfig(ConfigType type, const std::string &rootdir,
const shared_ptr<EncFSConfig> &config ); const shared_ptr<EncFSConfig> &config);
class EncFS_Context; 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);
#endif #endif

View File

@ -28,42 +28,24 @@
using namespace rel; using namespace rel;
using namespace rlog; 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,91 +91,74 @@ 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)
return 1; return 1;
else else
return 2; return 2;
} }
#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() );
return (cS * 3 + aS) * 3 + rS; return (cS * 3 + aS) * 3 + rS;
} }
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()) {
{ return (diffSum(A, B) < EqualVersion);
if( A.name() == B.name() )
{
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.
@ -40,8 +37,8 @@ namespace rel
Age - the difference between the newest and oldest interfaces that Age - the difference between the newest and oldest interfaces that
are implemented. are implemented.
*/ */
Interface( const char *name, int Current, int Revision, int Age ); Interface(const char *name, int Current, int Revision, int Age);
Interface( const std::string &name, int Current, int Revision, int Age); Interface(const std::string &name, int Current, int Revision, int Age);
Interface(const Interface &src); Interface(const Interface &src);
Interface(); Interface();
@ -50,7 +47,7 @@ namespace rel
// This checks the current() version and age() against B.current() for // This checks the current() version and age() against B.current() for
// compatibility. Even if A.implements(B) is true, B > A may also be // compatibility. Even if A.implements(B) is true, B > A may also be
// true, meaning B is a newer revision of the interface then A. // true, meaning B is a newer revision of the interface then A.
bool implements( const Interface &dst ) const; bool implements(const Interface &dst) const;
const std::string &name() const; const std::string &name() const;
int current() const; int current() const;
@ -62,26 +59,24 @@ namespace rel
int &revision(); int &revision();
int &age(); int &age();
Interface &operator = ( const Interface &src ); Interface &operator=(const Interface &src);
private: private:
std::string _name; std::string _name;
int _current; int _current;
int _revision; int _revision;
int _age; int _age;
}; };
} }
ConfigVar & operator << (ConfigVar &, const rel::Interface &); ConfigVar &operator<<(ConfigVar &, const rel::Interface &);
const ConfigVar & operator >> (const ConfigVar &, rel::Interface &); const ConfigVar &operator>>(const ConfigVar &, rel::Interface &);
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); 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);
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); 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,66 +51,45 @@ 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(randBytes >= 0);
rAssert( macBytes >= 0 && macBytes <= 8 );
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 { return MACFileIO_iface; }
int MACFileIO::open(int flags) { return base->open(flags); }
void MACFileIO::setFileName(const char *fileName) {
base->setFileName(fileName);
} }
rel::Interface MACFileIO::interface() const const char *MACFileIO::getFileName() const { return base->getFileName(); }
{
return MACFileIO_iface;
}
int MACFileIO::open( int flags ) bool MACFileIO::setIV(uint64_t iv) { return base->setIV(iv); }
{
return base->open( flags );
}
void MACFileIO::setFileName( const char *fileName ) inline static off_t roundUpDivide(off_t numerator, int denominator) {
{
base->setFileName( fileName );
}
const char *MACFileIO::getFileName() const
{
return base->getFileName();
}
bool MACFileIO::setIV( uint64_t iv )
{
return base->setIV( iv );
}
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.
return ( numerator + denominator - 1 ) / denominator; return (numerator + denominator - 1) / denominator;
} }
// Convert from a location in the raw file to a location when MAC headers are // Convert from a location in the raw file to a location when MAC headers are
@ -123,9 +102,8 @@ 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,175 +112,149 @@ 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;
stbuf->st_size = locWithoutHeader( stbuf->st_size, bs, headerSize ); stbuf->st_size = locWithoutHeader(stbuf->st_size, bs, headerSize);
} }
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;
MemBlock mb = MemoryPool::allocate( bs ); MemBlock mb = MemoryPool::allocate(bs);
IORequest tmp; IORequest tmp;
tmp.offset = locWithHeader( req.offset, bs, headerSize ); tmp.offset = locWithHeader(req.offset, bs, headerSize);
tmp.data = mb.data; tmp.data = mb.data;
tmp.dataLen = headerSize + req.dataLen; tmp.dataLen = headerSize + req.dataLen;
// get the data from the base FileIO layer // get the data from the base FileIO layer
ssize_t readSize = base->read( tmp ); ssize_t readSize = base->read(tmp);
// 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);
{ throw ERROR(_("MAC comparison failure, refusing to read"));
MemoryPool::release( mb );
throw ERROR(
_("MAC comparison failure, refusing to read"));
} }
} }
} }
// 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);
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;
// we have the unencrypted data, so we need to attach a header to it. // we have the unencrypted data, so we need to attach a header to it.
MemBlock mb = MemoryPool::allocate( bs ); MemBlock mb = MemoryPool::allocate(bs);
IORequest newReq; IORequest newReq;
newReq.offset = locWithHeader( req.offset, bs, headerSize ); newReq.offset = locWithHeader(req.offset, bs, headerSize);
newReq.data = mb.data; newReq.data = mb.data;
newReq.dataLen = headerSize + req.dataLen; newReq.dataLen = headerSize + req.dataLen;
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;
} }
} }
// now, we can let the next level have it.. // now, we can let the next level have it..
bool ok = base->write( newReq ); bool ok = base->write(newReq);
MemoryPool::release( mb ); MemoryPool::release(mb);
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,36 +24,34 @@
#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();
virtual rel::Interface interface() const; virtual rel::Interface interface() const;
virtual void setFileName( const char *fileName ); virtual void setFileName(const char *fileName);
virtual const char *getFileName() const; virtual const char *getFileName() const;
virtual bool setIV( uint64_t iv ); virtual bool setIV(uint64_t iv);
virtual int open( int flags ); virtual int open(int flags);
virtual int getAttr( struct stat *stbuf ) const; virtual int getAttr(struct stat *stbuf) const;
virtual off_t getSize() const; virtual off_t getSize() const;
virtual int truncate( off_t size ); virtual int truncate(off_t size);
virtual bool isWritable() const; virtual bool isWritable() const;
private: private:
virtual ssize_t readOneBlock( const IORequest &req ) const; virtual ssize_t readOneBlock(const IORequest &req) const;
virtual bool writeOneBlock( const IORequest &req ); virtual bool writeOneBlock(const IORequest &req);
shared_ptr<FileIO> base; shared_ptr<FileIO> base;
shared_ptr<Cipher> cipher; shared_ptr<Cipher> cipher;
@ -64,4 +62,3 @@ private:
}; };
#endif #endif

View File

@ -30,38 +30,34 @@
#ifdef HAVE_VALGRIND_MEMCHECK_H #ifdef HAVE_VALGRIND_MEMCHECK_H
#include <valgrind/memcheck.h> #include <valgrind/memcheck.h>
#else #else
#define VALGRIND_MAKE_MEM_NOACCESS( a, b ) #define VALGRIND_MAKE_MEM_NOACCESS(a, b)
#define VALGRIND_MAKE_MEM_UNDEFINED( a, b ) #define VALGRIND_MAKE_MEM_UNDEFINED(a, b)
#endif #endif
using namespace rlog; 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();
BUF_MEM_grow( block->data, size ); BUF_MEM_grow(block->data, size);
VALGRIND_MAKE_MEM_NOACCESS( block->data->data, block->data->max ); VALGRIND_MAKE_MEM_NOACCESS(block->data->data, block->data->max);
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 );
delete el; delete el;
} }
@ -69,77 +65,66 @@ 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) {
pthread_mutex_lock(&gMPoolMutex);
MemBlock MemoryPool::allocate( int size )
{
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
parent->next = block->next; parent->next = block->next;
} }
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;
result.data = BLOCKDATA(block); result.data = BLOCKDATA(block);
result.internalData = block; result.internalData = block;
VALGRIND_MAKE_MEM_UNDEFINED( result.data, size ); VALGRIND_MAKE_MEM_UNDEFINED(result.data, 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;
// just to be sure there's nothing important left in buffers.. // just to be sure there's nothing important left in buffers..
VALGRIND_MAKE_MEM_UNDEFINED( block->data->data, block->size ); VALGRIND_MAKE_MEM_UNDEFINED(block->data->data, block->size);
memset( BLOCKDATA(block) , 0, block->size); memset(BLOCKDATA(block), 0, block->size);
VALGRIND_MAKE_MEM_NOACCESS( block->data->data, block->data->max ); VALGRIND_MAKE_MEM_NOACCESS(block->data->data, block->data->max);
block->next = gMemPool; block->next = gMemPool;
gMemPool = block; gMemPool = block;
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;
gMemPool = NULL; gMemPool = NULL;
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,13 +23,11 @@
#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();
// leave the lock as it is. When the Lock wrapper is destroyed, it // leave the lock as it is. When the Lock wrapper is destroyed, it
@ -38,28 +36,20 @@ namespace rel
private: private:
Lock(const Lock &src); // not allowed Lock(const Lock &src); // not allowed
Lock &operator = (const Lock &src); // not allowed Lock &operator=(const Lock &src); // not allowed
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,50 +39,39 @@ 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;
Interface iface; Interface iface;
}; };
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;
tmp.iface = it->second.iface; tmp.iface = it->second.iface;
result.push_back( tmp ); result.push_back(tmp);
} }
} }
} }
@ -90,12 +79,10 @@ NameIO::GetAlgorithmList( bool includeHidden )
return result; return result;
} }
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;
@ -103,40 +90,35 @@ bool NameIO::Register( const char *name, const char *description,
alg.description = description; alg.description = description;
alg.iface = iface; alg.iface = iface;
gNameIOMap->insert( make_pair( string(name), alg )); gNameIOMap->insert(make_pair(string(name), alg));
return true; return true;
} }
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);
} }
} }
return result; return result;
} }
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,194 +126,148 @@ 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 bool NameIO::getReverseEncryption() const { return reverseEncryption; }
{
return chainedNameIV;
}
void NameIO::setReverseEncryption( bool enable ) std::string NameIO::recodePath(const char *path,
{
reverseEncryption = enable;
}
bool NameIO::getReverseEncryption() const
{
return reverseEncryption;
}
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;
} }
// 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)
// code the name // code the name
int codedLen = (this->*_code)( path, len, iv, codeBuf ); int codedLen = (this->*_code)(path, len, iv, codeBuf);
rAssert( codedLen <= approxLen ); rAssert(codedLen <= approxLen);
rAssert( codeBuf[codedLen] == '\0' ); rAssert(codeBuf[codedLen] == '\0');
path += len; path += len;
// append result to string // append result to string
output += (char*)codeBuf; output += (char *)codeBuf;
BUFFER_RESET( codeBuf ) BUFFER_RESET(codeBuf)
} }
} }
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)
// code the name // code the name
int codedLen = encodeName( plaintextName, length, 0, codeBuf ); int codedLen = encodeName(plaintextName, length, 0, codeBuf);
rAssert( codedLen <= approxLen ); rAssert(codedLen <= approxLen);
rAssert( codeBuf[codedLen] == '\0' ); rAssert(codeBuf[codedLen] == '\0');
// append result to string // append result to string
std::string result = (char*)codeBuf; std::string result = (char *)codeBuf;
BUFFER_RESET( codeBuf ) BUFFER_RESET(codeBuf)
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)
// code the name // code the name
int codedLen = decodeName( encodedName, length, 0, codeBuf ); int codedLen = decodeName(encodedName, length, 0, codeBuf);
rAssert( codedLen <= approxLen ); rAssert(codedLen <= approxLen);
rAssert( codeBuf[codedLen] == '\0' ); rAssert(codeBuf[codedLen] == '\0');
// append result to string // append result to string
std::string result = (char*)codeBuf; std::string result = (char *)codeBuf;
BUFFER_RESET( codeBuf ) BUFFER_RESET(codeBuf)
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,85 +31,80 @@
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 shared_ptr<Cipher> &cipher, const CipherKey &key); 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;
}; };
typedef std::list<Algorithm> AlgorithmList; typedef std::list<Algorithm> AlgorithmList;
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,
static shared_ptr<NameIO> New( const std::string &name, const CipherKey &key);
const shared_ptr<Cipher> &cipher, const CipherKey &key); static shared_ptr<NameIO> New(const std::string &name,
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();
virtual rel::Interface interface() const =0; virtual rel::Interface interface() const = 0;
void setChainedNameIV( bool enable ); void setChainedNameIV(bool enable);
bool getChainedNameIV() const; bool getChainedNameIV() const;
void setReverseEncryption( bool enable ); void setReverseEncryption(bool enable);
bool getReverseEncryption() const; bool getReverseEncryption() const;
std::string encodePath( const char *plaintextPath ) const; std::string encodePath(const char *plaintextPath) const;
std::string decodePath( const char *encodedPath ) const; std::string decodePath(const char *encodedPath) const;
std::string encodePath( const char *plaintextPath, uint64_t *iv ) const; std::string encodePath(const char *plaintextPath, uint64_t *iv) const;
std::string decodePath( const char *encodedPath, uint64_t *iv ) const; std::string decodePath(const char *encodedPath, uint64_t *iv) const;
virtual int maxEncodedNameLen( int plaintextNameLen ) const =0; virtual int maxEncodedNameLen(int plaintextNameLen) const = 0;
virtual int maxDecodedNameLen( int encodedNameLen ) const =0; virtual int maxDecodedNameLen(int encodedNameLen) const = 0;
std::string encodeName( const char *plaintextName, int length ) const; std::string encodeName(const char *plaintextName, int length) const;
std::string decodeName( const char *encodedName, int length ) const; std::string decodeName(const char *encodedName, int length) const;
protected: protected:
virtual int encodeName( const char *plaintextName, int length, virtual int encodeName(const char *plaintextName, int length,
char *encodedName ) const; char *encodedName) const;
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;
std::string _encodePath( const char *plaintextPath, uint64_t *iv ) const; std::string _encodePath(const char *plaintextPath, uint64_t *iv) const;
std::string _decodePath( const char *encodedPath, uint64_t *iv ) const; std::string _decodePath(const char *encodedPath, uint64_t *iv) const;
std::string _encodeName( const char *plaintextName, int length ) const; std::string _encodeName(const char *plaintextName, int length) const;
std::string _decodeName( const char *encodedName, int length ) const; std::string _decodeName(const char *encodedName, int length) const;
bool chainedNameIV; bool chainedNameIV;
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
@ -117,22 +112,18 @@ private:
BUFFER_RESET should be called for the same name as BUFFER_INIT BUFFER_RESET should be called for the same name as BUFFER_INIT
*/ */
#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>
@ -32,122 +31,85 @@ using namespace std;
using namespace rel; using namespace rel;
using namespace rlog; using namespace rlog;
static Interface NullInterface( "nullCipher", 1, 0, 0 ); 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 &) {}
~NullDestructor() {} ~NullDestructor() {}
NullDestructor &operator = (const NullDestructor &){ return *this; } NullDestructor &operator=(const NullDestructor &) { return *this; }
void operator ()(NullKey *&) {} void operator()(NullKey *&) {}
}; };
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;
@ -165,20 +126,14 @@ bool NullCipher::streamDecode( unsigned char *src, int len,
return true; return true;
} }
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,11 +28,10 @@
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:
NullCipher(const rel::Interface &iface); NullCipher(const rel::Interface &iface);
virtual ~NullCipher(); virtual ~NullCipher();
@ -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,30 +23,29 @@
#include "NameIO.h" #include "NameIO.h"
class NullNameIO : public NameIO class NullNameIO : public NameIO {
{ public:
public:
static rel::Interface CurrentInterface(); static rel::Interface CurrentInterface();
NullNameIO( ); NullNameIO();
virtual ~NullNameIO(); virtual ~NullNameIO();
virtual rel::Interface interface() const; virtual rel::Interface interface() const;
virtual int maxEncodedNameLen( int plaintextNameLen ) const; virtual int maxEncodedNameLen(int plaintextNameLen) const;
virtual int maxDecodedNameLen( int encodedNameLen ) const; virtual int maxDecodedNameLen(int encodedNameLen) const;
// hack to help with static builds // hack to help with static builds
static bool Enabled(); static bool Enabled();
protected:
virtual int encodeName( const char *plaintextName, int length, protected:
uint64_t *iv, char *encodedName ) const; virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
virtual int decodeName( const char *encodedName, int length, char *encodedName) const;
uint64_t *iv, char *plaintextName ) const; virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
private: char *plaintextName) const;
private:
}; };
#endif #endif

View File

@ -21,13 +21,12 @@
#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);
Range(int min, int max, int increment); Range(int min, int max, int increment);
@ -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
@ -92,22 +77,13 @@ inline int Range::closest(int value) const
tmp += (increment >> 1); tmp += (increment >> 1);
tmp -= (tmp % increment); tmp -= (tmp % increment);
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,20 +81,17 @@ 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 );
} }
return fd; return fd;
@ -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,37 +114,31 @@ 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
int newFd = ::open( name.c_str(), finalFlags ); int newFd = ::open(name.c_str(), finalFlags);
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,145 +146,118 @@ 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 );
int retrys = 10; int retrys = 10;
void *buf = req.data; void *buf = req.data;
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;
} }
bytes -= writeSize; bytes -= writeSize;
offset += writeSize; offset += writeSize;
buf = (void*)((char*)buf + writeSize); buf = (void *)((char *)buf + writeSize);
--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);
#endif #endif
} 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,31 +25,30 @@
#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);
virtual ~RawFileIO(); virtual ~RawFileIO();
virtual rel::Interface interface() const; virtual rel::Interface interface() const;
virtual void setFileName( const char *fileName ); virtual void setFileName(const char *fileName);
virtual const char *getFileName() const; virtual const char *getFileName() const;
virtual int open( int flags ); virtual int open(int flags);
virtual int getAttr( struct stat *stbuf ) const; virtual int getAttr(struct stat *stbuf) const;
virtual off_t getSize() const; virtual off_t getSize() const;
virtual ssize_t read( const IORequest & req ) const; virtual ssize_t read(const IORequest &req) const;
virtual bool write( const IORequest &req ); virtual bool write(const IORequest &req);
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

File diff suppressed because it is too large Load Diff

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;
@ -77,7 +76,7 @@ class SSL_Cipher : public Cipher
unsigned int _keySize; // in bytes unsigned int _keySize; // in bytes
unsigned int _ivLength; unsigned int _ivLength;
public: public:
SSL_Cipher(const rel::Interface &iface, const rel::Interface &realIface, SSL_Cipher(const rel::Interface &iface, const rel::Interface &realIface,
const EVP_CIPHER *blockCipher, const EVP_CIPHER *streamCipher, const EVP_CIPHER *blockCipher, const EVP_CIPHER *streamCipher,
int keyLength); int keyLength);
@ -97,54 +96,50 @@ 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;
// functional interfaces // functional interfaces
/* /*
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:
void setIVec( unsigned char *ivec, uint64_t seed, private:
const shared_ptr<SSLKey> &key ) const; void setIVec(unsigned char *ivec, uint64_t seed,
const shared_ptr<SSLKey> &key) const;
// deprecated - for backward compatibility // deprecated - for backward compatibility
void setIVec_old( unsigned char *ivec, unsigned int seed, void setIVec_old(unsigned char *ivec, unsigned int seed,
const shared_ptr<SSLKey> &key ) const; const shared_ptr<SSLKey> &key) const;
}; };
#endif #endif

View File

@ -32,17 +32,16 @@
using namespace rel; 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,145 +64,117 @@ 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);
} }
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;
encodeBegin = (unsigned char *)encodedName; encodeBegin = (unsigned char *)encodedName;
} }
// stream encode the plaintext bytes // stream encode the plaintext bytes
memcpy( encodeBegin, plaintextName, length ); memcpy(encodeBegin, plaintextName, length);
_cipher->nameEncode( encodeBegin, length, (uint64_t)mac ^ tmpIV, _key); _cipher->nameEncode(encodeBegin, length, (uint64_t)mac ^ tmpIV, _key);
// convert the entire thing to base 64 ascii.. // convert the entire thing to base 64 ascii..
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);
// decode into tmpBuf, because this step produces more data then we can fit // decode into tmpBuf, because this step produces more data then we can fit
// into the result buffer.. // into the result buffer..
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 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);
} }
// use nameDeocde instead of streamDecode for backward compatibility // use nameDeocde instead of streamDecode for backward compatibility
_cipher->nameDecode( (unsigned char *)plaintextName, decodedStreamLen, _cipher->nameDecode((unsigned char *)plaintextName, decodedStreamLen,
(uint64_t)mac ^ tmpIV, _key); (uint64_t)mac ^ tmpIV, _key);
// compute MAC to check with stored value // compute MAC to check with stored value
unsigned int mac2 = _cipher->MAC_16((const unsigned char *)plaintextName, unsigned int mac2 = _cipher->MAC_16((const unsigned char *)plaintextName,
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");
} }
return decodedStreamLen; return decodedStreamLen;
} }
bool StreamNameIO::Enabled() bool StreamNameIO::Enabled() { return true; }
{
return true;
}

View File

@ -26,34 +26,32 @@
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();
virtual rel::Interface interface() const; virtual rel::Interface interface() const;
virtual int maxEncodedNameLen( int plaintextNameLen ) const; virtual int maxEncodedNameLen(int plaintextNameLen) const;
virtual int maxDecodedNameLen( int encodedNameLen ) const; virtual int maxDecodedNameLen(int encodedNameLen) const;
// hack to help with static builds // hack to help with static builds
static bool Enabled(); static bool Enabled();
protected:
virtual int encodeName( const char *plaintextName, int length, protected:
uint64_t *iv, char *encodedName ) const; virtual int encodeName(const char *plaintextName, int length, uint64_t *iv,
virtual int decodeName( const char *encodedName, int length, char *encodedName) const;
uint64_t *iv, char *plaintextName ) const; virtual int decodeName(const char *encodedName, int length, uint64_t *iv,
private: char *plaintextName) const;
private:
int _interface; int _interface;
shared_ptr<Cipher> _cipher; shared_ptr<Cipher> _cipher;
CipherKey _key; CipherKey _key;
}; };
#endif #endif

View File

@ -27,23 +27,20 @@
// 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;
unsigned char *origDst = dst; unsigned char *origDst = dst;
const int mask = (1 << dst2Pow) -1; const int mask = (1 << dst2Pow) - 1;
// 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, const int mask = (1 << dst2Pow) - 1;
int workBits, if (!outLoc) outLoc = src;
unsigned char *outLoc)
{
const int mask = (1 << dst2Pow) -1;
if(!outLoc)
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,19 +111,16 @@ 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
ch += 'A' - 12; ch += 'A' - 12;
} else } else
ch = B642AsciiTable[ ch ]; ch = B642AsciiTable[ch];
in[offset] = ch; in[offset] = ch;
} }
@ -148,36 +128,29 @@ void B64ToAscii(unsigned char *in, int length)
static const unsigned char Ascii2B64Table[] = 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
ch += 12 - 'A'; ch += 12 - 'A';
} else } else
ch = Ascii2B64Table[ ch ] - '0'; ch = Ascii2B64Table[ch] - '0';
*out++ = ch; *out++ = ch;
} }
} }
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:
explicit iserializer() : protected:
basic_iserializer( explicit iserializer()
boost::serialization::singleton< : basic_iserializer(boost::serialization::singleton<
BOOST_DEDUCED_TYPENAME BOOST_DEDUCED_TYPENAME boost::serialization::
boost::serialization::type_info_implementation<EncFSConfig>::type type_info_implementation<
>::get_const_instance() EncFSConfig>::type>::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);
@ -69,28 +62,20 @@ public:
virtual bool is_polymorphic() const { virtual bool is_polymorphic() const {
return boost::is_polymorphic<EncFSConfig>::value; return boost::is_polymorphic<EncFSConfig>::value;
} }
virtual ~iserializer(){}; virtual ~iserializer() {};
}; };
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>
@ -54,7 +53,7 @@
#include <rlog/Error.h> #include <rlog/Error.h>
#ifndef MIN #ifndef MIN
#define MIN(a,b) (((a)<(b)) ? (a): (b)) #define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif #endif
#define ESUCCESS 0 #define ESUCCESS 0
@ -64,82 +63,74 @@ using namespace rlog;
using rel::Lock; using rel::Lock;
using namespace boost; using namespace boost;
#define GET_FN(ctx, finfo) ctx->getNode((void*)(uintptr_t)finfo->fh) #define GET_FN(ctx, finfo) ctx->getNode((void *)(uintptr_t)finfo->fh)
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);
} }
return res; return res;
} }
// 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)
fnode = GET_FN(ctx, fi); fnode = GET_FN(ctx, fi);
else else
fnode = FSRoot->lookupNode( path, opName ); fnode = FSRoot->lookupNode(path, opName);
rAssert(fnode.get() != NULL); rAssert(fnode.get() != NULL);
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);
} }
return res; return res;
} }
@ -155,26 +146,22 @@ 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';
stbuf->st_size = FSRoot->plainPath( buf.get() ).length(); stbuf->st_size = FSRoot->plainPath(buf.get()).length();
res = ESUCCESS; res = ESUCCESS;
} else } else
@ -185,237 +172,201 @@ 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);
rLog(Info, "symlink %s -> %s", fromCName.c_str(), toCName.c_str()); rLog(Info, "symlink %s -> %s", fromCName.c_str(), toCName.c_str());
@ -423,191 +374,159 @@ 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) {
return withFileNode("truncate", path, NULL, _do_truncate, size);
} }
int encfs_truncate(const char *path, off_t size) int encfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi) {
{ return withFileNode("ftruncate", path, fi, _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 _do_utime(EncFS_Context *, const string &cyName, struct utimbuf *buf) {
{ int res = utime(cyName.c_str(), buf);
return withFileNode( "ftruncate", path, fi, _do_truncate, size );
}
int _do_utime(EncFS_Context *, const string &cyName, struct utimbuf *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;
tv[1].tv_sec = ts[1].tv_sec; tv[1].tv_sec = ts[1].tv_sec;
tv[1].tv_usec = ts[1].tv_nsec / 1000; tv[1].tv_usec = ts[1].tv_nsec / 1000;
int res = lutimes( cyName.c_str(), tv); int res = lutimes(cyName.c_str(), tv);
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);
} }
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,188 +534,158 @@ 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;
else else
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);
} }
return res; return res;
} }
#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);
#else #else
int res = ::removexattr( cyName.c_str(), name ); int res = ::removexattr(cyName.c_str(), name);
#endif #endif
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);
@ -87,23 +82,22 @@ int encfs_fsync(const char *path, int flags, struct fuse_file_info *info);
#ifdef HAVE_XATTR #ifdef HAVE_XATTR
# 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);
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);
# endif
int encfs_listxattr( const char *path, char *list, size_t size );
int encfs_removexattr( const char *path, const char *name );
#endif #endif
int encfs_utimens( const char *path, const struct timespec ts[2] ); int encfs_listxattr(const char *path, char *list, size_t size);
int encfs_removexattr(const char *path, const char *name);
#endif #endif
int encfs_utimens(const char *path, const struct timespec ts[2]);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -25,8 +25,6 @@
#include "intl/gettext.h" #include "intl/gettext.h"
// make shortcut for gettext // make shortcut for gettext
# 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,60 +86,62 @@ 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) "; if (opts->useStdin) ss << "(useStdin) ";
if(opts->useStdin) ss << "(useStdin) "; if (opts->annotate) ss << "(annotate) ";
if(opts->annotate) ss << "(annotate) "; 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) ss << fuseArgv[i] << ' ';
for(int i=0; i<fuseArgc; ++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,38 +150,33 @@ 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;
int argc = 2; int argc = 2;
const char *argv[] = {"...", "-h"}; const char *argv[] = {"...", "-h"};
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) \
rAssert(out->fuseArgc < MaxFuseArgs); \ do { \
out->fuseArgv[out->fuseArgc++] = (ARG); } while(0) rAssert(out->fuseArgc < MaxFuseArgs); \
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;
@ -226,15 +219,13 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
{"stdinpass", 0, 0, 'S'}, // read password from stdin {"stdinpass", 0, 0, 'S'}, // read password from stdin
{"annotate", 0, 0, 513}, // Print annotation lines to stderr {"annotate", 0, 0, 513}, // Print annotation lines to stderr
{"verbose", 0, 0, 'v'}, // verbose mode {"verbose", 0, 0, 'v'}, // verbose mode
{"version", 0, 0, 'V'}, //version {"version", 0, 0, 'V'}, // version
{"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;
@ -280,7 +269,7 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
PUSHARG("-d"); PUSHARG("-d");
break; break;
case 'i': case 'i':
out->idleTimeout = strtol( optarg, (char**)NULL, 10); out->idleTimeout = strtol(optarg, (char **)NULL, 10);
out->opts->idleTracking = true; out->opts->idleTracking = true;
break; break;
case 'k': case 'k':
@ -303,16 +292,15 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
break; break;
case 'o': case 'o':
PUSHARG("-o"); PUSHARG("-o");
PUSHARG( optarg ); PUSHARG(optarg);
break; break;
case 'p': case 'p':
out->opts->passwordProgram.assign( optarg ); out->opts->passwordProgram.assign(optarg);
break; break;
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;
} }
@ -448,95 +418,87 @@ bool processArgs(int argc, char *argv[], const shared_ptr<EncFS_Args> &out)
return true; return true;
} }
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
conn->async_read = true; conn->async_read = true;
// 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;
} }
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..
rDebug("waking up monitoring thread"); rDebug("waking up monitoring thread");
pthread_mutex_lock( &ctx->wakeupMutex ); pthread_mutex_lock(&ctx->wakeupMutex);
pthread_cond_signal( &ctx->wakeupCond ); pthread_cond_signal(&ctx->wakeupCond);
pthread_mutex_unlock( &ctx->wakeupMutex ); pthread_mutex_unlock(&ctx->wakeupMutex);
rDebug("joining with idle monitoring thread"); rDebug("joining with idle monitoring thread");
pthread_join( ctx->monitorThread , 0 ); pthread_join(ctx->monitorThread, 0);
rDebug("join done"); rDebug("join done");
} }
} }
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);
#if defined(ENABLE_NLS) && defined(LOCALEDIR) #if defined(ENABLE_NLS) && defined(LOCALEDIR)
setlocale( LC_ALL, "" ); setlocale(LC_ALL, "");
bindtextdomain( PACKAGE, LOCALEDIR ); bindtextdomain(PACKAGE, LOCALEDIR);
textdomain( PACKAGE ); textdomain(PACKAGE);
#endif #endif
// log to stderr by default.. // log to stderr by default..
scoped_ptr<StdioNode> slog( new StdioNode( STDERR_FILENO ) ); scoped_ptr<StdioNode> slog(new StdioNode(STDERR_FILENO));
scoped_ptr<SyslogNode> logNode; scoped_ptr<SyslogNode> logNode;
// show error and warning output // show error and warning output
slog->subscribeTo( GetGlobalChannel("error") ); slog->subscribeTo(GetGlobalChannel("error"));
slog->subscribeTo( GetGlobalChannel("warning") ); slog->subscribeTo(GetGlobalChannel("warning"));
// anything that comes from the user should be considered tainted until // anything that comes from the user should be considered tainted until
// we've processed it and only allowed through what we support. // we've processed it and only allowed through what we support.
shared_ptr<EncFS_Args> encfsArgs( new EncFS_Args ); shared_ptr<EncFS_Args> encfsArgs(new EncFS_Args);
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"));
} }
rDebug("Root directory: %s", encfsArgs->opts->rootDir.c_str()); rDebug("Root directory: %s", encfsArgs->opts->rootDir.c_str());
@ -575,56 +537,54 @@ int main(int argc, char *argv[])
encfs_oper.listxattr = encfs_listxattr; encfs_oper.listxattr = encfs_listxattr;
encfs_oper.removexattr = encfs_removexattr; encfs_oper.removexattr = encfs_removexattr;
#endif // HAVE_XATTR #endif // HAVE_XATTR
//encfs_oper.opendir = encfs_opendir; // encfs_oper.opendir = encfs_opendir;
//encfs_oper.readdir = encfs_readdir; // encfs_oper.readdir = encfs_readdir;
//encfs_oper.releasedir = encfs_releasedir; // encfs_oper.releasedir = encfs_releasedir;
//encfs_oper.fsyncdir = encfs_fsyncdir; // encfs_oper.fsyncdir = encfs_fsyncdir;
encfs_oper.init = encfs_init; encfs_oper.init = encfs_init;
encfs_oper.destroy = encfs_destroy; encfs_oper.destroy = encfs_destroy;
//encfs_oper.access = encfs_access; // encfs_oper.access = encfs_access;
//encfs_oper.create = encfs_create; // encfs_oper.create = encfs_create;
encfs_oper.ftruncate = encfs_ftruncate; encfs_oper.ftruncate = encfs_ftruncate;
encfs_oper.fgetattr = encfs_fgetattr; encfs_oper.fgetattr = encfs_fgetattr;
//encfs_oper.lock = encfs_lock; // encfs_oper.lock = encfs_lock;
encfs_oper.utimens = encfs_utimens; encfs_oper.utimens = encfs_utimens;
//encfs_oper.bmap = encfs_bmap; // encfs_oper.bmap = encfs_bmap;
#if (__FreeBSD__ >= 10) || defined(__APPLE__) #if (__FreeBSD__ >= 10) || defined(__APPLE__)
// encfs_oper.setvolname // encfs_oper.setvolname
// encfs_oper.exchange // encfs_oper.exchange
// encfs_oper.getxtimes // encfs_oper.getxtimes
// encfs_oper.setbkuptime // encfs_oper.setbkuptime
// encfs_oper.setchgtime // encfs_oper.setchgtime
// encfs_oper.setcrtime // encfs_oper.setcrtime
// encfs_oper.chflags // encfs_oper.chflags
// encfs_oper.setattr_x // encfs_oper.setattr_x
// encfs_oper.fsetattr_x // encfs_oper.fsetattr_x
#endif #endif
openssl_init( encfsArgs->isThreaded ); openssl_init(encfsArgs->isThreaded);
// context is not a smart pointer because it will live for the life of // context is not a smart pointer because it will live for the life of
// the filesystem. // the filesystem.
EncFS_Context *ctx = new EncFS_Context; EncFS_Context *ctx = new EncFS_Context;
ctx->publicFilesystem = encfsArgs->opts->ownerCreate; ctx->publicFilesystem = encfsArgs->opts->ownerCreate;
RootPtr rootInfo = initFS( ctx, encfsArgs->opts ); RootPtr rootInfo = initFS(ctx, encfsArgs->opts);
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.
encfsArgs->opts->delayMount = false; encfsArgs->opts->delayMount = false;
// set the globally visible root directory node // set the globally visible root directory node
ctx->setRoot( rootInfo->root ); ctx->setRoot(rootInfo->root);
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"
@ -634,76 +594,70 @@ int main(int argc, char *argv[])
// reset umask now, since we don't want it to interfere with the // reset umask now, since we don't want it to interfere with the
// 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"));
logNode->subscribeTo( GetGlobalChannel("error") ); logNode->subscribeTo(GetGlobalChannel("error"));
// disable stderr reporting.. // disable stderr reporting..
slog.reset(); slog.reset();
// keep around a pointer just in case we end up needing it to // keep around a pointer just in case we end up needing it to
// report a fatal condition later (fuse_main exits unexpectedly)... // report a fatal condition later (fuse_main exits unexpectedly)...
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
// immediately.. // immediately..
time( &startTime ); time(&startTime);
// 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");
// xgroup(usage) // xgroup(usage)
fprintf(out, _("fuse failed. Common problems:\n" fprintf(out, _("fuse failed. Common problems:\n"
" - fuse kernel module not installed (modprobe fuse)\n" " - fuse kernel module not installed (modprobe fuse)\n"
" - 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"));
} }
} }
// cleanup so that we can check for leaked resources.. // cleanup so that we can check for leaked resources..
rootInfo.reset(); rootInfo.reset();
ctx->setRoot( shared_ptr<DirNode>() ); ctx->setRoot(shared_ptr<DirNode>());
MemoryPool::destroyAll(); MemoryPool::destroyAll();
openssl_shutdown( encfsArgs->isThreaded ); openssl_shutdown(encfsArgs->isThreaded);
return returnCode; return returnCode;
} }
@ -718,76 +672,65 @@ 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;
const int timeoutCycles = 60 * arg->idleTimeout / ActivityCheckInterval; const int timeoutCycles = 60 * arg->idleTimeout / ActivityCheckInterval;
int idleCycles = 0; int idleCycles = 0;
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())
++idleCycles; ++idleCycles;
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;
} }
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);
rDebug("Idle monitoring thread exiting"); rDebug("Idle monitoring thread exiting");
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"),
arg->mountPoint.c_str()); arg->mountPoint.c_str());
fuse_unmount( arg->mountPoint.c_str() ); fuse_unmount(arg->mountPoint.c_str());
return true; return true;
} }
} }

View File

@ -31,23 +31,20 @@
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
string b64Key = cipher->encodeAsString( key, key ); string b64Key = cipher->encodeAsString(key, key);
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;
} }
@ -58,9 +55,8 @@ int main(int argc, char **argv)
openssl_init(false); openssl_init(false);
// get a list of the available algorithms // get a list of the available algorithms
shared_ptr<Cipher> cipher = Cipher::New( type, size ); shared_ptr<Cipher> cipher = Cipher::New(type, size);
genKey( cipher ); genKey(cipher);
//openssl_shutdown(false); // openssl_shutdown(false);
} }

View File

@ -31,55 +31,45 @@
#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)
{ pthread_mutex_destroy(crypto_locks + i);
for(int i=0; i<CRYPTO_num_locks(); ++i)
pthread_mutex_destroy( crypto_locks+i );
delete[] crypto_locks; delete[] crypto_locks;
crypto_locks = NULL; crypto_locks = NULL;
} }
} }
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();
unsigned int randSeed = 0; unsigned int randSeed = 0;
RAND_bytes( (unsigned char*)&randSeed, sizeof(randSeed) ); RAND_bytes((unsigned char *)&randSeed, sizeof(randSeed));
srand( randSeed ); srand(randSeed);
#ifndef OPENSSL_NO_ENGINE #ifndef OPENSSL_NO_ENGINE
/* Load all bundled ENGINEs into memory and make them visible */ /* Load all bundled ENGINEs into memory and make them visible */
@ -88,22 +78,18 @@ 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);
CRYPTO_set_locking_callback( pthreads_locking_callback ); CRYPTO_set_locking_callback(pthreads_locking_callback);
} }
} }
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"
@ -50,23 +52,21 @@ static const char rcsid[] = "$OpenBSD: readpassphrase.c,v 1.12 2001/12/15 05:41:
#include <readpassphrase.h> #include <readpassphrase.h>
#ifdef TCSASOFT #ifdef TCSASOFT
# define _T_FLUSH (TCSAFLUSH|TCSASOFT) #define _T_FLUSH (TCSAFLUSH | TCSASOFT)
#else #else
# define _T_FLUSH (TCSAFLUSH) #define _T_FLUSH (TCSAFLUSH)
#endif #endif
/* SunOS 4.x which lacks _POSIX_VDISABLE, but has VDISABLE */ /* SunOS 4.x which lacks _POSIX_VDISABLE, but has VDISABLE */
#if !defined(_POSIX_VDISABLE) && defined(VDISABLE) #if !defined(_POSIX_VDISABLE) && defined(VDISABLE)
# define _POSIX_VDISABLE VDISABLE #define _POSIX_VDISABLE VDISABLE
#endif #endif
static volatile sig_atomic_t signo; 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;
@ -77,7 +77,7 @@ readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
/* I suppose we could alloc on demand in this case (XXX). */ /* I suppose we could alloc on demand in this case (XXX). */
if (bufsiz == 0) { if (bufsiz == 0) {
errno = EINVAL; errno = EINVAL;
return(NULL); return (NULL);
} }
restart: restart:
@ -88,7 +88,7 @@ restart:
if ((input = output = open(_PATH_TTY, O_RDWR)) == -1) { if ((input = output = open(_PATH_TTY, O_RDWR)) == -1) {
if (flags & RPP_REQUIRE_TTY) { if (flags & RPP_REQUIRE_TTY) {
errno = ENOTTY; errno = ENOTTY;
return(NULL); return (NULL);
} }
input = STDIN_FILENO; input = STDIN_FILENO;
output = STDERR_FILENO; output = STDERR_FILENO;
@ -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
@ -174,7 +168,7 @@ restart:
} }
errno = save_errno; errno = save_errno;
return(nr == -1 ? NULL : buf); return (nr == -1 ? NULL : buf);
} }
#endif /* HAVE_READPASSPHRASE */ #endif /* HAVE_READPASSPHRASE */
@ -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,112 +47,80 @@
#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;
} }
if(size != FSBlockSize) if (size != FSBlockSize)
cipher->streamEncode( data.data, size, 0, key ); cipher->streamEncode(data.data, size, 0, key);
else else
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);
} }
if(size != FSBlockSize) if (size != FSBlockSize)
cipher->streamDecode( data.data, size, 0, key ); cipher->streamDecode(data.data, size, 0, key);
else else
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);
MemoryPool::release( orig ); MemoryPool::release(orig);
return numByteErrors; return numByteErrors;
} }
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,56 +130,47 @@ 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();
unsigned char *keyBuf = new unsigned char [ encodedKeySize ]; unsigned char *keyBuf = new unsigned char[encodedKeySize];
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();
unsigned char *keyBuf = new unsigned char [ encodedKeySize ]; unsigned char *keyBuf = new unsigned char[encodedKeySize];
cipher->writeKey( key, keyBuf, encodingKey ); cipher->writeKey(key, keyBuf, encodingKey);
// store in config struct.. // store in config struct..
EncFSConfig cfg; EncFSConfig cfg;
cfg.cipherIface = cipher->interface(); cfg.cipherIface = cipher->interface();
cfg.keySize = 8 * cipher->keySize(); cfg.keySize = 8 * cipher->keySize();
cfg.blockSize = FSBlockSize; cfg.blockSize = FSBlockSize;
cfg.assignKeyData( keyBuf, encodedKeySize ); cfg.assignKeyData(keyBuf, encodedKeySize);
// save config // save config
string data; string data;
@ -229,28 +188,22 @@ bool runTests(const shared_ptr<Cipher> &cipher, bool verbose)
} }
// check.. // check..
rAssert( cfg.cipherIface.implements(cfg2.cipherIface) ); rAssert(cfg.cipherIface.implements(cfg2.cipherIface));
rAssert( cfg.keySize == cfg2.keySize ); rAssert(cfg.keySize == cfg2.keySize);
rAssert( cfg.blockSize == cfg2.blockSize ); rAssert(cfg.blockSize == cfg2.blockSize);
// 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;
} }
} }
@ -261,195 +214,163 @@ bool runTests(const shared_ptr<Cipher> &cipher, bool verbose)
fsCfg->config.reset(new EncFSConfig); fsCfg->config.reset(new EncFSConfig);
fsCfg->config->blockSize = FSBlockSize; fsCfg->config->blockSize = FSBlockSize;
if(verbose) if (verbose)
cerr << "Testing name encode/decode (stream coding w/ IV chaining)\n"; cerr << "Testing name encode/decode (stream coding w/ IV chaining)\n";
{ {
fsCfg->opts.reset(new EncFS_Opts); fsCfg->opts.reset(new EncFS_Opts);
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)
cerr << "Testing name encode/decode (block coding w/ IV chaining)\n"; cerr << "Testing name encode/decode (block coding w/ IV chaining)\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() ) ); 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;
}
}
if (verbose) cerr << "Testing block encode/decode on full block - ";
{
int numErrors = checkErrorPropogation(cipher, FSBlockSize, -1, key);
if (numErrors) {
if (verbose) cerr << " FAILED!\n";
return false; return false;
} else {
if (verbose) cerr << " OK\n";
}
}
if (verbose) cerr << "Testing block encode/decode on partial block - ";
{
int numErrors = checkErrorPropogation(cipher, FSBlockSize - 1, -1, key);
if (numErrors) {
if (verbose) cerr << " FAILED!\n";
return false;
} else {
if (verbose) cerr << " OK\n";
} }
} }
if(verbose) if (verbose) cerr << "Checking error propogation in partial block:\n";
cerr << "Testing block encode/decode on full block - ";
{ {
int numErrors = checkErrorPropogation( cipher, int minChanges = FSBlockSize - 1;
FSBlockSize, -1, key );
if(numErrors)
{
if(verbose)
cerr << " FAILED!\n";
return false;
} else
{
if(verbose)
cerr << " OK\n";
}
}
if(verbose)
cerr << "Testing block encode/decode on partial block - ";
{
int numErrors = checkErrorPropogation( cipher,
FSBlockSize-1, -1, key );
if(numErrors)
{
if(verbose)
cerr << " FAILED!\n";
return false;
} else
{
if(verbose)
cerr << " OK\n";
}
}
if(verbose)
cerr << "Checking error propogation in partial block:\n";
{
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[]) {
RLogInit(argc, argv);
int main(int argc, char *argv[]) StdioNode stdLog(STDERR_FILENO);
{ stdLog.subscribeTo(RLOG_CHANNEL("error"));
RLogInit( argc, argv ); stdLog.subscribeTo(RLOG_CHANNEL("warning"));
StdioNode stdLog( STDERR_FILENO );
stdLog.subscribeTo( RLOG_CHANNEL("error") );
stdLog.subscribeTo( RLOG_CHANNEL("warning") );
#ifndef NO_DEBUG #ifndef NO_DEBUG
stdLog.subscribeTo( RLOG_CHANNEL("debug") ); stdLog.subscribeTo(RLOG_CHANNEL("debug"));
#endif #endif
#ifdef HAVE_SSL #ifdef HAVE_SSL
@ -464,20 +385,16 @@ int main(int argc, char *argv[])
#endif #endif
#endif #endif
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 "
{ << blockSize << ": ";
cerr << it->name << ", key length " << keySize
<< ", 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,22 +428,17 @@ 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";
runTests( cipher, true ); runTests(cipher, true);
} }
MemoryPool::destroyAll(); MemoryPool::destroyAll();
return 0; return 0;
} }