358 lines
11 KiB
C++
358 lines
11 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.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// filemanipulator.cpp -- Provides functionality to examine tripwire file headers
|
|
// for file type and encryption type. Also provides a mechanism for
|
|
// changing encryption keys or removing encryption.
|
|
//
|
|
|
|
#include "stdtw.h"
|
|
#include "filemanipulator.h"
|
|
#include "core/serializerimpl.h"
|
|
#include "twutil.h"
|
|
#include "fcodatabasefile.h"
|
|
#include "fcoreport.h"
|
|
#include "configfile.h"
|
|
#include "policyfile.h"
|
|
#include "headerinfo.h"
|
|
#include "core/usernotify.h"
|
|
#include "twcrypto/crypto.h"
|
|
#include "util/fileutil.h"
|
|
#include "tw/twstrings.h"
|
|
#include "core/displayencoder.h"
|
|
|
|
//=============================================================================
|
|
// class cFileManipulator
|
|
//=============================================================================
|
|
|
|
cFileManipulator::cFileManipulator(const TCHAR* filename)
|
|
{
|
|
mbInit = false;
|
|
mFileName = filename;
|
|
}
|
|
|
|
cFileManipulator::cFileManipulator(const cFileManipulator& rhs)
|
|
: mFileName(rhs.mFileName),
|
|
mFileHeader(rhs.mFileHeader)
|
|
{
|
|
}
|
|
|
|
cFileManipulator::~cFileManipulator()
|
|
{
|
|
}
|
|
|
|
void cFileManipulator::Init()
|
|
{
|
|
if (cFileUtil::FileExists(mFileName))
|
|
{
|
|
cFileArchive arch;
|
|
try
|
|
{
|
|
try
|
|
{
|
|
arch.OpenRead( mFileName.c_str() );
|
|
}
|
|
catch (eArchive&)
|
|
{
|
|
throw eFileManipFileRead( mFileName );
|
|
}
|
|
|
|
cSerializerImpl s(arch, cSerializerImpl::S_READ);
|
|
mFileHeader.Read(&s);
|
|
}
|
|
catch (eArchive&)
|
|
{
|
|
throw eFileManipHeaderNotFound( mFileName );
|
|
}
|
|
catch (eSerializer&)
|
|
{
|
|
throw eFileManipHeaderNotFound( mFileName );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw eFileManipFileNotFound( mFileName );
|
|
}
|
|
mbInit = true;
|
|
}
|
|
|
|
const cFileHeaderID* cFileManipulator::GetHeaderID()
|
|
{
|
|
ASSERT( mbInit );
|
|
if (!mbInit)
|
|
{
|
|
// return NULL;
|
|
Init();
|
|
}
|
|
return &mFileHeader.GetID();
|
|
}
|
|
|
|
uint32 cFileManipulator::GetFileVersion()
|
|
{
|
|
ASSERT( mbInit );
|
|
if (!mbInit)
|
|
{
|
|
// return 0;
|
|
Init();
|
|
}
|
|
return mFileHeader.GetVersion();
|
|
}
|
|
|
|
cFileHeader::Encoding cFileManipulator::GetEncoding()
|
|
{
|
|
ASSERT( mbInit );
|
|
if (!mbInit)
|
|
{
|
|
// return (cFileHeader::Encoding)0;
|
|
Init();
|
|
}
|
|
return mFileHeader.GetEncoding();
|
|
}
|
|
|
|
// Try to decrypt the file using the given key. If thorough is true then
|
|
// the entire file is read into memory. Returns true if decryption was
|
|
// successful.
|
|
bool cFileManipulator::TestDecryption(const cElGamalSigPublicKey& key, bool thorough)
|
|
{
|
|
// TODO: pay attention to thorough flag. For now we will just always act thoroughly.
|
|
|
|
ASSERT( mbInit );
|
|
if (!mbInit)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool fError = false;
|
|
|
|
// "turn down" the verbosity of iUserNotify to V_NORMAL it it is V_VERBOSE to make output a little cleaner
|
|
bool fChangedVerbosity = false;
|
|
int savedVerbosity = iUserNotify::GetInstance()->GetVerboseLevel();
|
|
if( savedVerbosity == iUserNotify::V_VERBOSE )
|
|
{
|
|
iUserNotify::GetInstance()->SetVerboseLevel( iUserNotify::V_NORMAL );
|
|
fChangedVerbosity = true;
|
|
}
|
|
|
|
try
|
|
{
|
|
if (mFileHeader.GetID() == cFCODatabaseFile::GetFileHeaderID())
|
|
{
|
|
cFCODatabaseFile db;
|
|
bool encrypted;
|
|
cTWUtil::ReadDatabase(mFileName.c_str(), db, &key, encrypted);
|
|
}
|
|
else if (mFileHeader.GetID() == cFCOReport::GetFileHeaderID())
|
|
{
|
|
cFCOReport rep;
|
|
cFCOReportHeader reph;
|
|
bool encrypted;
|
|
cTWUtil::ReadReport(mFileName.c_str(), reph, rep, &key, true, encrypted);
|
|
}
|
|
else if (mFileHeader.GetID() == cConfigFile::GetFileHeaderID())
|
|
{
|
|
// read the embedded key from config file and see if it is the same
|
|
// as the public key passed in.
|
|
cMemoryArchive memArch;
|
|
TSTRING configText; //not used
|
|
cTWUtil::ReadConfigText( mFileName.c_str(), configText, &memArch );
|
|
memArch.Seek( 0, cBidirArchive::BEGINNING );
|
|
|
|
// only do the test if there is baggage (indicating the cfg file is encrypted)
|
|
if( memArch.Length() > 0 )
|
|
{
|
|
// create the two public keys...
|
|
cElGamalSigPublicKey pubKey( memArch.GetMemory() );
|
|
|
|
// compare the two ....
|
|
if( ! pubKey.IsEqual( key ) )
|
|
throw ePoly();
|
|
}
|
|
}
|
|
else if (mFileHeader.GetID() == cPolicyFile::GetFileHeaderID())
|
|
{
|
|
std::string policyText;
|
|
cTWUtil::ReadPolicyText(mFileName.c_str(), policyText, &key);
|
|
}
|
|
else
|
|
throw ePoly();
|
|
}
|
|
catch (eError&)
|
|
{
|
|
fError = true;
|
|
}
|
|
|
|
// reset verbosity
|
|
if( fChangedVerbosity )
|
|
iUserNotify::GetInstance()->SetVerboseLevel( savedVerbosity );
|
|
|
|
return( fError == false );
|
|
}
|
|
|
|
// Change the encryption on a file.
|
|
// If pNewKey is NULL, then encryption on the file will be removed.
|
|
// If pOldKey is NULL and the file is currently encrypted, then the
|
|
// function will throw eFileManip;
|
|
// If pOldKey is not NULL and the file is encrypted, then the fuction
|
|
// will throw eFileManip;
|
|
// If pOldKey is NULL and pNewKey is NULL and the file is not
|
|
// currently encrypted, the function will not do anything and will just
|
|
// return.
|
|
// Returns on successful encryption change.
|
|
void cFileManipulator::ChangeEncryption(const cElGamalSigPublicKey* pOldKey, const cElGamalSigPrivateKey* pNewKey, bool backup)
|
|
{
|
|
ASSERT( mbInit );
|
|
if (!mbInit)
|
|
{
|
|
Init();
|
|
}
|
|
|
|
// check the pOldKey matches the current encryption state
|
|
if (mFileHeader.GetEncoding() != cFileHeader::ASYM_ENCRYPTION)
|
|
{
|
|
if (pOldKey != NULL)
|
|
throw eFileManipNotEncrypted( mFileName );
|
|
if (pNewKey == NULL)
|
|
return; // NOOP
|
|
}
|
|
else if (pOldKey == NULL)
|
|
throw eFileManipMissingKey();
|
|
|
|
if (!cFileUtil::FileWritable(mFileName))
|
|
throw eFileManipNotWritable( mFileName );
|
|
|
|
if (mFileHeader.GetID() == cFCODatabaseFile::GetFileHeaderID())
|
|
{
|
|
cFCODatabaseFile db;
|
|
bool encrypted;
|
|
|
|
cTWUtil::ReadDatabase(mFileName.c_str(), db, pOldKey, encrypted);
|
|
if (backup)
|
|
{
|
|
TSTRING backname = mFileName + iFSServices::GetInstance()->GetStandardBackupExtension();
|
|
iFSServices::GetInstance()->Rename(mFileName.c_str(), backname.c_str());
|
|
}
|
|
|
|
cTWUtil::WriteDatabase(mFileName.c_str(), db, pNewKey != NULL, pNewKey);
|
|
return;
|
|
}
|
|
else if (mFileHeader.GetID() == cFCOReport::GetFileHeaderID())
|
|
{
|
|
cFCOReport rep;
|
|
cFCOReportHeader reph;
|
|
bool encrypted;
|
|
cTWUtil::ReadReport(mFileName.c_str(), reph, rep, pOldKey, false, encrypted);
|
|
if (backup)
|
|
{
|
|
TSTRING backname = mFileName + iFSServices::GetInstance()->GetStandardBackupExtension();
|
|
iFSServices::GetInstance()->Rename(mFileName.c_str(), backname.c_str());
|
|
}
|
|
cTWUtil::WriteReport(mFileName.c_str(), reph, rep, pNewKey != NULL, pNewKey);
|
|
return;
|
|
}
|
|
else if (mFileHeader.GetID() == cConfigFile::GetFileHeaderID())
|
|
{
|
|
TSTRING configText;
|
|
|
|
iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, _T("%s%s\n"),
|
|
TSS_GetString( cTW, tw::STR_OPEN_CONFIG_FILE).c_str(),
|
|
cDisplayEncoder::EncodeInline( mFileName ).c_str());
|
|
|
|
cTWUtil::ReadConfigText(mFileName.c_str(), configText);
|
|
if (backup)
|
|
{
|
|
TSTRING backname = mFileName + iFSServices::GetInstance()->GetStandardBackupExtension();
|
|
iFSServices::GetInstance()->Rename(mFileName.c_str(), backname.c_str());
|
|
}
|
|
|
|
cTWUtil::WriteConfigText(mFileName.c_str(), configText, pNewKey != NULL, pNewKey);
|
|
|
|
return;
|
|
}
|
|
else if (mFileHeader.GetID() == cPolicyFile::GetFileHeaderID())
|
|
{
|
|
std::string policyText;
|
|
|
|
iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, _T("%s%s\n"),
|
|
TSS_GetString( cTW, tw::STR_OPEN_POLICY_FILE).c_str(),
|
|
cDisplayEncoder::EncodeInline( mFileName ).c_str());
|
|
|
|
cTWUtil::ReadPolicyText(mFileName.c_str(), policyText, pOldKey);
|
|
if (backup)
|
|
{
|
|
TSTRING backname = mFileName + iFSServices::GetInstance()->GetStandardBackupExtension();
|
|
iFSServices::GetInstance()->Rename(mFileName.c_str(), backname.c_str());
|
|
}
|
|
|
|
cTWUtil::WritePolicyText(mFileName.c_str(), policyText, pNewKey != NULL, pNewKey);
|
|
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
// method for getting a list of manipulators
|
|
// returns number of files matched
|
|
int cFileManipulator::LoadFiles(std::list<cFileManipulator>& ret, TSTRING mask)
|
|
{
|
|
ret.clear();
|
|
|
|
// TODO: we need to be able to deal with masks for the NT version.
|
|
// Right now *.* will not work in NT. We should not get a '*' for unix.
|
|
|
|
try
|
|
{
|
|
ret.push_back(cFileManipulator(mask.c_str()));
|
|
}
|
|
catch (eError&)
|
|
{
|
|
// file does not exist
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
bool cFileManipulator::UseSiteKey(const cFileHeaderID& headerID)
|
|
{
|
|
if (headerID == cFCODatabaseFile::GetFileHeaderID() ||
|
|
headerID == cFCOReport::GetFileHeaderID())
|
|
return false;
|
|
else
|
|
if (headerID == cConfigFile::GetFileHeaderID() ||
|
|
headerID == cPolicyFile::GetFileHeaderID())
|
|
return true;
|
|
|
|
ASSERT(false); // what could it be? be careful not to en/decrypt keyfiles.
|
|
return false;
|
|
}
|
|
|