// // 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& 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; }