477 lines
15 KiB
C++
477 lines
15 KiB
C++
//
|
|
// The developer of the original code and/or files is Tripwire, Inc.
|
|
// Portions created by Tripwire, Inc. are copyright (C) 2000 Tripwire,
|
|
// Inc. Tripwire is a registered trademark of Tripwire, Inc. All rights
|
|
// reserved.
|
|
//
|
|
// This program is free software. The contents of this file are subject
|
|
// to the terms of the GNU General Public License as published by the
|
|
// Free Software Foundation; either version 2 of the License, or (at your
|
|
// option) any later version. You may redistribute it and/or modify it
|
|
// only in compliance with the GNU General Public License.
|
|
//
|
|
// This program is distributed in the hope that it will be useful.
|
|
// However, this program is distributed AS-IS WITHOUT ANY
|
|
// WARRANTY; INCLUDING THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS
|
|
// FOR A PARTICULAR PURPOSE. Please see the GNU General Public License
|
|
// for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
// USA.
|
|
//
|
|
// Nothing in the GNU General Public License or any other license to use
|
|
// the code or files shall permit you to use Tripwire's trademarks,
|
|
// service marks, or other intellectual property without Tripwire's
|
|
// prior written consent.
|
|
//
|
|
// If you have any questions, please contact Tripwire, Inc. at either
|
|
// info@tripwire.org or www.tripwire.org.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// fspropcalc.cpp
|
|
|
|
#include "stdfs.h"
|
|
#include "core/debug.h"
|
|
#include "core/errorbucket.h"
|
|
#include "core/errorbucket.h"
|
|
#include "fco/fconame.h"
|
|
#include "fco/fconametranslator.h"
|
|
#include "fco/twfactory.h"
|
|
#include "fspropcalc.h"
|
|
#include "fsobject.h"
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
cFSPropCalc::cFSPropCalc() :
|
|
mCollAction(iFCOPropCalc::PROP_LEAVE), mCalcFlags(0), mpErrorBucket(0)
|
|
{
|
|
}
|
|
|
|
cFSPropCalc::~cFSPropCalc()
|
|
{
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// NeedsStat -- returns true if any properties are in the vector that require
|
|
// a stat() call
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
static bool NeedsStat(const cFCOPropVector& v)
|
|
{
|
|
return ( v.ContainsItem(cFSPropSet::PROP_DEV) ||
|
|
v.ContainsItem(cFSPropSet::PROP_RDEV) ||
|
|
v.ContainsItem(cFSPropSet::PROP_INODE) ||
|
|
v.ContainsItem(cFSPropSet::PROP_MODE) ||
|
|
v.ContainsItem(cFSPropSet::PROP_NLINK) ||
|
|
v.ContainsItem(cFSPropSet::PROP_UID) ||
|
|
v.ContainsItem(cFSPropSet::PROP_GID) ||
|
|
v.ContainsItem(cFSPropSet::PROP_SIZE) ||
|
|
v.ContainsItem(cFSPropSet::PROP_ATIME) ||
|
|
v.ContainsItem(cFSPropSet::PROP_MTIME) ||
|
|
v.ContainsItem(cFSPropSet::PROP_CTIME) ||
|
|
v.ContainsItem(cFSPropSet::PROP_BLOCK_SIZE) ||
|
|
v.ContainsItem(cFSPropSet::PROP_BLOCKS) ||
|
|
v.ContainsItem(cFSPropSet::PROP_FILETYPE) ||
|
|
v.ContainsItem(cFSPropSet::PROP_GROWING_FILE)
|
|
);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// GetSymLinkStr -- returns a string that represents what a symbolic link is
|
|
// pointing at. If this returns false, call iFSServices::GetErrnoString()
|
|
// to get the error message.
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
static bool GetSymLinkStr(const TSTRING& strName, cArchive& arch)
|
|
{
|
|
char buf[1024]; // TODO: is this big enough?
|
|
#if defined(O_PATH)
|
|
int fd = open(strName.c_str(), (O_PATH | O_NOFOLLOW | O_NOATIME));
|
|
int rtn = readlinkat(fd, 0, buf, 1024);
|
|
close(fd);
|
|
#else
|
|
int rtn = readlink( strName.c_str(), buf, 1024 );
|
|
#endif
|
|
|
|
if(rtn == -1)
|
|
return false;
|
|
|
|
// the return value is the number of characters written.
|
|
arch.WriteBlob(buf, rtn);
|
|
|
|
return true;
|
|
}
|
|
|
|
void cFSPropCalc::AddPropCalcError(const eError& e)
|
|
{
|
|
if(mpErrorBucket)
|
|
mpErrorBucket->AddError(e);
|
|
}
|
|
|
|
bool cFSPropCalc::DoStat( const TSTRING& strName, cFSStatArgs& statArgs )
|
|
{
|
|
cDebug d("cFSPropCalc::DoStat");
|
|
|
|
try
|
|
{
|
|
d.TraceDetail("---Performing Stat()\n");
|
|
iFSServices::GetInstance()->Stat(strName, statArgs);
|
|
}
|
|
catch(eError& e)
|
|
{
|
|
d.TraceError("Error getting stat info for %s : %s\n", strName.c_str(), e.GetMsg().c_str());
|
|
e.SetFatality(false);
|
|
AddPropCalcError(e);
|
|
return false;
|
|
}
|
|
catch(std::exception& e)
|
|
{
|
|
d.TraceError("Error getting stat info for %s : %s\n", strName.c_str(), e.what());
|
|
AddPropCalcError( eFSPropCalc( strName, e.what(), eError::NON_FATAL ) );
|
|
return false;
|
|
}
|
|
catch(...)
|
|
{
|
|
d.TraceError("Unknown error getting stat info for %s\n", strName.c_str());
|
|
AddPropCalcError( eFSPropCalc( strName, "unknown", eError::NON_FATAL ) );
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool cFSPropCalc::DoOpen( const TSTRING& strName, cFileArchive& arch )
|
|
{
|
|
try
|
|
{
|
|
arch.OpenRead(strName.c_str(), ((mCalcFlags & iFCOPropCalc::DIRECT_IO) ?
|
|
cFileArchive::FA_SCANNING | cFileArchive::FA_DIRECT :
|
|
cFileArchive::FA_SCANNING) );
|
|
}
|
|
catch (eError&)
|
|
{
|
|
AddPropCalcError( eArchiveOpen( strName, iFSServices::GetInstance()->GetErrString(), eError::NON_FATAL));
|
|
return false;
|
|
}
|
|
catch (std::exception& e)
|
|
{
|
|
AddPropCalcError( eArchiveOpen( strName, e.what(), eError::NON_FATAL ) );
|
|
return false;
|
|
}
|
|
catch (...)
|
|
{
|
|
AddPropCalcError( eArchiveOpen( strName, "unknown", eError::NON_FATAL ) );
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool cFSPropCalc::DoHash( const TSTRING& strName, cBidirArchive* pTheArch, cArchiveSigGen& asg, cFileArchive& arch )
|
|
{
|
|
cDebug d("cFSPropCalc::DoHash");
|
|
try
|
|
{
|
|
pTheArch->Seek( 0, cBidirArchive::BEGINNING );
|
|
asg.CalculateSignatures( *pTheArch );
|
|
arch.Close();
|
|
}
|
|
catch (eError& e)
|
|
{
|
|
d.TraceError("Error generating hashes for %s : %s\n", strName.c_str(), e.GetMsg().c_str());
|
|
e.SetFatality(false);
|
|
AddPropCalcError(e);
|
|
return false;
|
|
}
|
|
catch (std::exception& e)
|
|
{
|
|
d.TraceError("Error generating hashes for %s : %s\n", strName.c_str(), e.what());
|
|
AddPropCalcError( eArchiveRead( strName, e.what(), eError::NON_FATAL ) );
|
|
return false;
|
|
}
|
|
catch (...)
|
|
{
|
|
d.TraceError("Unknown error generating hashes for %s\n", strName.c_str());
|
|
AddPropCalcError( eArchiveRead( strName, "unknown", eError::NON_FATAL ) );
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void cFSPropCalc::HandleStatProperties( const cFCOPropVector& propsToCheck, const cFSStatArgs& ss, cFSPropSet& propSet)
|
|
{
|
|
if(propsToCheck.ContainsItem(cFSPropSet::PROP_DEV))
|
|
propSet.SetDev(ss.dev);
|
|
|
|
if(propsToCheck.ContainsItem(cFSPropSet::PROP_RDEV))
|
|
propSet.SetRDev(ss.rdev);
|
|
|
|
if(propsToCheck.ContainsItem(cFSPropSet::PROP_INODE))
|
|
propSet.SetInode(ss.ino);
|
|
|
|
if(propsToCheck.ContainsItem(cFSPropSet::PROP_MODE))
|
|
propSet.SetMode(ss.mode);
|
|
|
|
if(propsToCheck.ContainsItem(cFSPropSet::PROP_NLINK))
|
|
propSet.SetNLink(ss.nlink);
|
|
|
|
if(propsToCheck.ContainsItem(cFSPropSet::PROP_UID))
|
|
propSet.SetUID(ss.uid);
|
|
|
|
if(propsToCheck.ContainsItem(cFSPropSet::PROP_GID))
|
|
propSet.SetGID(ss.gid);
|
|
|
|
if(propsToCheck.ContainsItem(cFSPropSet::PROP_SIZE))
|
|
propSet.SetSize(ss.size);
|
|
|
|
if(propsToCheck.ContainsItem(cFSPropSet::PROP_ATIME))
|
|
propSet.SetAccessTime(ss.atime);
|
|
|
|
if(propsToCheck.ContainsItem(cFSPropSet::PROP_MTIME))
|
|
propSet.SetModifyTime(ss.mtime);
|
|
|
|
if(propsToCheck.ContainsItem(cFSPropSet::PROP_CTIME))
|
|
propSet.SetCreateTime(ss.ctime);
|
|
|
|
if(propsToCheck.ContainsItem(cFSPropSet::PROP_BLOCK_SIZE))
|
|
propSet.SetBlockSize(ss.blksize);
|
|
|
|
if(propsToCheck.ContainsItem(cFSPropSet::PROP_BLOCKS))
|
|
propSet.SetBlocks(ss.blocks);
|
|
|
|
if(propsToCheck.ContainsItem(cFSPropSet::PROP_GROWING_FILE))
|
|
propSet.SetGrowingFile(ss.size);
|
|
|
|
if(propsToCheck.ContainsItem(cFSPropSet::PROP_FILETYPE))
|
|
{
|
|
// TODO -- It _really_ bites duplicating code here and in fsdatasource.cpp
|
|
// *** This _has_ to be remedied somehow!
|
|
// set the file type
|
|
switch(ss.mFileType)
|
|
{
|
|
case cFSStatArgs::TY_FILE:
|
|
propSet.SetFileType(cFSPropSet::FT_FILE);
|
|
break;
|
|
case cFSStatArgs::TY_DIR:
|
|
propSet.SetFileType(cFSPropSet::FT_DIR);
|
|
break;
|
|
case cFSStatArgs::TY_BLOCKDEV:
|
|
propSet.SetFileType(cFSPropSet::FT_BLOCKDEV);
|
|
break;
|
|
case cFSStatArgs::TY_CHARDEV:
|
|
propSet.SetFileType(cFSPropSet::FT_CHARDEV);
|
|
break;
|
|
case cFSStatArgs::TY_SYMLINK:
|
|
propSet.SetFileType(cFSPropSet::FT_SYMLINK);
|
|
break;
|
|
case cFSStatArgs::TY_FIFO:
|
|
propSet.SetFileType(cFSPropSet::FT_FIFO);
|
|
break;
|
|
case cFSStatArgs::TY_SOCK:
|
|
propSet.SetFileType(cFSPropSet::FT_SOCK);
|
|
break;
|
|
case cFSStatArgs::TY_DOOR:
|
|
propSet.SetFileType(cFSPropSet::FT_DOOR);
|
|
break;
|
|
case cFSStatArgs::TY_PORT:
|
|
propSet.SetFileType(cFSPropSet::FT_PORT);
|
|
break;
|
|
default:
|
|
// set it to invalid
|
|
propSet.SetFileType(cFSPropSet::FT_INVALID);
|
|
}
|
|
}
|
|
}
|
|
|
|
void cFSPropCalc::HandleHashes( const cFCOPropVector& propsToCheck, const TSTRING& strName, cFSPropSet& propSet)
|
|
{
|
|
bool hash_success = false;
|
|
|
|
// if the file type is not a regular file, we will
|
|
// not try to open the file for signature generation
|
|
ASSERT( propSet.GetValidVector().ContainsItem(cFSPropSet::PROP_FILETYPE) );
|
|
if( propSet.GetFileType() == cFSPropSet::FT_FILE || propSet.GetFileType() == cFSPropSet::FT_SYMLINK )
|
|
{
|
|
if( // if we need to open the file
|
|
propsToCheck.ContainsItem(cFSPropSet::PROP_CRC32) ||
|
|
propsToCheck.ContainsItem(cFSPropSet::PROP_MD5) ||
|
|
propsToCheck.ContainsItem(cFSPropSet::PROP_SHA) ||
|
|
propsToCheck.ContainsItem(cFSPropSet::PROP_HAVAL)
|
|
)
|
|
{
|
|
cFileArchive arch;
|
|
cMemoryArchive memArch;
|
|
cBidirArchive* pTheArch;
|
|
hash_success = true;
|
|
|
|
if(propSet.GetFileType() == cFSPropSet::FT_SYMLINK)
|
|
{
|
|
pTheArch = &memArch;
|
|
if(! GetSymLinkStr(strName, memArch))
|
|
{
|
|
// add it to the bucket...
|
|
AddPropCalcError( eArchiveOpen( strName, iFSServices::GetInstance()->GetErrString(), eError::NON_FATAL ) );
|
|
hash_success = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pTheArch = &arch;
|
|
hash_success = DoOpen(strName, arch);
|
|
}
|
|
|
|
//
|
|
// if we have successfully initialized the archive
|
|
//
|
|
if (hash_success)
|
|
{
|
|
cArchiveSigGen asg;
|
|
|
|
if(propsToCheck.ContainsItem(cFSPropSet::PROP_CRC32))
|
|
{
|
|
propSet.SetDefinedCRC32(true);
|
|
asg.AddSig( propSet.GetCRC32() );
|
|
}
|
|
|
|
if(propsToCheck.ContainsItem(cFSPropSet::PROP_MD5))
|
|
{
|
|
propSet.SetDefinedMD5(true);
|
|
asg.AddSig( propSet.GetMD5() );
|
|
}
|
|
|
|
if(propsToCheck.ContainsItem(cFSPropSet::PROP_SHA))
|
|
{
|
|
propSet.SetDefinedSHA(true);
|
|
asg.AddSig( propSet.GetSHA() );
|
|
}
|
|
|
|
if(propsToCheck.ContainsItem(cFSPropSet::PROP_HAVAL))
|
|
{
|
|
propSet.SetDefinedHAVAL(true);
|
|
asg.AddSig( propSet.GetHAVAL() );
|
|
}
|
|
|
|
//
|
|
// calculate the signatures
|
|
//
|
|
hash_success = DoHash(strName, pTheArch, asg, arch);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!hash_success)
|
|
{
|
|
// We can't calculate signatures, set them to undefined
|
|
if (propsToCheck.ContainsItem(cFSPropSet::PROP_CRC32))
|
|
propSet.SetDefinedCRC32(false);
|
|
|
|
if (propsToCheck.ContainsItem(cFSPropSet::PROP_MD5))
|
|
propSet.SetDefinedMD5(false);
|
|
|
|
if (propsToCheck.ContainsItem(cFSPropSet::PROP_SHA))
|
|
propSet.SetDefinedSHA(false);
|
|
|
|
if (propsToCheck.ContainsItem(cFSPropSet::PROP_HAVAL))
|
|
propSet.SetDefinedHAVAL(false);
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// VisitFSObject -- this is the workhorse method that actually fills out the
|
|
// passed in FSObject' properties
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void cFSPropCalc::VisitFSObject(cFSObject& obj)
|
|
{
|
|
cDebug d("cFSPropCalc::VisitFSObject");
|
|
d.TraceDetail(_T("Visiting %s\n"), obj.GetName().AsString().c_str());
|
|
|
|
// if we are not in overwrite mode, we need to alter the
|
|
// properties we are calculating...
|
|
cFCOPropVector propsToCheck(mPropVector);
|
|
if(mCollAction == iFCOPropCalc::PROP_LEAVE)
|
|
{
|
|
cFCOPropVector inBoth = propsToCheck;
|
|
inBoth &= obj.GetPropSet()->GetValidVector();
|
|
propsToCheck ^= inBoth;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
d.TraceDetail("----->Collision Action = %s\n", mCollAction == iFCOPropCalc::PROP_LEAVE ? "Leave" : "Replace");
|
|
d.TraceDetail("----->Object's valid properties (a):\n");
|
|
obj.GetPropSet()->GetValidVector().TraceContents(cDebug::D_DETAIL);
|
|
d.TraceDetail("----->Properties to calculate: (b)\n");
|
|
mPropVector.TraceContents(cDebug::D_DETAIL);
|
|
d.TraceDetail("----->Properties to change in object ((a&b)^b for Leave or b for Replace):\n");
|
|
propsToCheck.TraceContents(cDebug::D_DETAIL);
|
|
#endif //_DEBUG
|
|
|
|
// only do the stat() if it is necessary
|
|
cFSStatArgs ss;
|
|
TSTRING strName = iTWFactory::GetInstance()->GetNameTranslator()->ToStringAPI( obj.GetName() );
|
|
|
|
// get a reference to the fco's property set
|
|
cFSPropSet& propSet = obj.GetFSPropSet();
|
|
|
|
//
|
|
// just return if this object is invalid
|
|
//
|
|
if( propSet.GetFileType() == cFSPropSet::FT_INVALID )
|
|
return;
|
|
|
|
if( NeedsStat(propsToCheck) )
|
|
{
|
|
if (!DoStat(strName, ss))
|
|
return;
|
|
|
|
HandleStatProperties(propsToCheck, ss, propSet);
|
|
}
|
|
|
|
HandleHashes(propsToCheck, strName, propSet);
|
|
}
|
|
|
|
void cFSPropCalc::SetPropVector(const cFCOPropVector& pv)
|
|
{
|
|
mPropVector = pv;
|
|
}
|
|
|
|
const cFCOPropVector& cFSPropCalc::GetPropVector() const
|
|
{
|
|
return mPropVector;
|
|
}
|
|
|
|
iFCOVisitor* cFSPropCalc::GetVisitor()
|
|
{
|
|
return this;
|
|
}
|
|
|
|
const iFCOVisitor* cFSPropCalc::GetVisitor() const
|
|
{
|
|
return this;
|
|
}
|
|
|
|
void cFSPropCalc::SetErrorBucket(cErrorBucket* pBucket)
|
|
{
|
|
mpErrorBucket = pBucket;
|
|
}
|
|
|
|
const cErrorBucket* cFSPropCalc::GetErrorBucket() const
|
|
{
|
|
return mpErrorBucket;
|
|
}
|
|
|
|
iFCOPropCalc::CollisionAction cFSPropCalc::GetCollisionAction() const
|
|
{
|
|
return mCollAction;
|
|
}
|
|
|
|
void cFSPropCalc::SetCollisionAction(CollisionAction a)
|
|
{
|
|
ASSERT((a == iFCOPropCalc::PROP_OVERWRITE) || (a == PROP_LEAVE));
|
|
mCollAction = a;
|
|
}
|
|
|