tripwire-open-source/src/tw/twutil.cpp

1492 lines
51 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.
//
///////////////////////////////////////////////////////////////////////////////
// twutil.cpp
//
#include "stdtw.h"
#include "twutil.h"
#include "twcrypto/crypto.h"
#include "core/archive.h"
#include "core/serializerimpl.h"
#include "twcrypto/cryptoarchive.h"
#include "fcoreport.h"
#include "twcrypto/keyfile.h"
#include "fco/fcospeclist.h"
#include "fco/genreswitcher.h"
#include "core/errorbucketimpl.h"
#include "core/cmdlineparser.h"
#include "configfile.h"
#include "core/fileheader.h"
#include "core/usernotify.h"
#include "policyfile.h"
#include "core/serstring.h"
#include "headerinfo.h"
#include "systeminfo.h"
#include "core/errorgeneral.h"
#include "fco/parsergenreutil.h"
#include "fco/twfactory.h"
#include "fco/fconame.h"
#include "fcodatabasefile.h"
#include "util/fileutil.h"
#include "core/stringutil.h"
#include "tw/twstrings.h"
#include "tw/twerrors.h"
#include "core/ntmbs.h"
#include "core/displayencoder.h"
#ifdef TW_PROFILE
#include "core/tasktimer.h"
#endif
#include "core/fsservices.h" // for the util_IsDir() stuff
#if IS_UNIX
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>
#include "core/tw_signal.h"
int _getch(void);
#endif
#ifdef _UNICODE // right now we only need this for unicode
#include <mbstring.h>
#endif
// constants
static const char* POLICY_FILE_MAGIC_8BYTE = "#POLTXT\n";
static const char* CONFIG_FILE_MAGIC_8BYTE = "#CFGTXT\n";
static const uint32 CURRENT_FIXED_VERSION = 0x02020000;
///////////////////////////////////////////////////////////////////////////////
// WriteObjectToArchive -- called from WriteObject, does most of the work
///////////////////////////////////////////////////////////////////////////////
static void WriteObjectToArchive(cArchive &arch, const TCHAR* filename, // filename is used only for issuing error messages
const iTypedSerializable* pObjHeader, const iTypedSerializable& obj,
cFileHeader& fileHeader, bool bEncrypt, const cElGamalSigPrivateKey* pPrivateKey)
{
try
{
// Set file version.
// If we in the future we wish to support reading databases of different versions,
// we will have to move this set to outside WriteObject().
fileHeader.SetVersion(CURRENT_FIXED_VERSION);
fileHeader.SetEncoding(bEncrypt ? cFileHeader::ASYM_ENCRYPTION : cFileHeader::COMPRESSED);
{
cSerializerImpl fhSer(arch, cSerializerImpl::S_WRITE, filename);
fileHeader.Write(&fhSer);
}
if (bEncrypt)
{
cElGamalSigArchive cryptoArchive;
cryptoArchive.SetWrite(&arch, pPrivateKey);
cSerializerImpl ser(cryptoArchive, cSerializerImpl::S_WRITE, filename);
ser.Init();
if(pObjHeader)
ser.WriteObject(pObjHeader);
ser.WriteObject(&obj);
ser.Finit();
cryptoArchive.FlushWrite();
}
else
{
// not encrypted
cNullCryptoArchive cryptoArchive;
cryptoArchive.Start(&arch);
cSerializerImpl ser(cryptoArchive, cSerializerImpl::S_WRITE, filename);
ser.Init();
if(pObjHeader)
ser.WriteObject(pObjHeader);
ser.WriteObject(&obj);
ser.Finit();
cryptoArchive.Finish();
}
}
catch (eError& e)
{
throw ePoly(
e.GetID(),
cErrorUtil::MakeFileError( e.GetMsg(), filename ),
e.GetFlags() );
}
}
///////////////////////////////////////////////////////////////////////////////
// WriteObject -- template class that writes an object to disk (ie -- report,
// db, etc) either encrypted or unencrypted.
// The only requrement on the object is that it is typed serializable.
// errorMsg is a number that can be passed to iUserString to indicate an
// appropriate error message if the object fails to load
//
// 10/30 -- this function has been expanded to take two objects -- a header and
// an object. Both are typed serializable, but the header can be NULL if
// none is desired.
///////////////////////////////////////////////////////////////////////////////
static void WriteObject(const TCHAR* filename, const iTypedSerializable* pObjHeader, const iTypedSerializable& obj,
cFileHeader& fileHeader, bool bEncrypt, const cElGamalSigPrivateKey* pPrivateKey)
{
cDebug d("WriteObject");
d.TraceDebug(_T("Writing %s to file %s\n"), obj.GetType().AsString(), filename);
ASSERT(pPrivateKey || (! bEncrypt));
cFileArchive arch;
if (!cFileUtil::IsRegularFile(filename) && cFileUtil::FileExists(filename))
throw eArchiveNotRegularFile( filename );
try
{
arch.OpenReadWrite( filename );
}
catch (eArchive&)
{
// probably better to rethrow this as a write failed exception
throw eArchiveWrite( filename, iFSServices::GetInstance()->GetErrString() ) ;
}
WriteObjectToArchive(arch, filename, pObjHeader, obj, fileHeader, bEncrypt, pPrivateKey);
arch.Close();
}
///////////////////////////////////////////////////////////////////////////////
// WriteObjectToArchive -- called from WriteObject, does most of the work
///////////////////////////////////////////////////////////////////////////////
static void ReadObjectFromArchive(cArchive &arch, const TCHAR* objFileName, iTypedSerializable* pObjHeader, iTypedSerializable& obj, const cFileHeaderID& fhid, const cElGamalSigPublicKey* pPublicKey, bool& bEncrypted)
{
cFileHeader fileHeader;
{
cSerializerImpl fhSer(arch, cSerializerImpl::S_READ, objFileName);
fileHeader.Read(&fhSer);
}
// check for a mismatched header
if (fileHeader.GetID() != fhid)
ThrowAndAssert(eSerializerInputStreamFmt(_T(""), objFileName, eSerializer::TY_FILE));
// Check file version.
// If we in the future we wish to support reading objects of different versions,
// we will have to move this check to outside ReadObject().
if (fileHeader.GetVersion() != CURRENT_FIXED_VERSION)
ThrowAndAssert(eSerializerVersionMismatch(_T(""), objFileName, eSerializer::TY_FILE));
try
{
// switch on the type of encoding...
if(fileHeader.GetEncoding() == cFileHeader::ASYM_ENCRYPTION)
{
// tell the user the db is encrypted
iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, TSS_GetString( cTW, tw::STR_FILE_ENCRYPTED).c_str());
bEncrypted = true;
if (pPublicKey == 0)
ThrowAndAssert(eSerializerEncryption(_T("")));
cElGamalSigArchive cryptoArchive;
cryptoArchive.SetRead(&arch, pPublicKey);
cSerializerImpl ser(cryptoArchive, cSerializerImpl::S_READ, objFileName);
ser.Init();
if(pObjHeader)
ser.ReadObject(pObjHeader);
ser.ReadObject(&obj);
ser.Finit();
}
else if(fileHeader.GetEncoding() == cFileHeader::COMPRESSED)
{
//not encrypted db...
bEncrypted = false;
cNullCryptoArchive cryptoArchive;
cryptoArchive.Start(&arch);
cSerializerImpl ser(cryptoArchive, cSerializerImpl::S_READ, objFileName);
ser.Init();
if(pObjHeader)
ser.ReadObject(pObjHeader);
ser.ReadObject(&obj);
ser.Finit();
}
else
// unknown encoding...
ThrowAndAssert(eSerializerInputStreamFmt(_T("")));
}
catch (eError& e)
{
// include filename in error msg
throw ePoly(
e.GetID(),
cErrorUtil::MakeFileError( e.GetMsg(), objFileName ),
e.GetFlags() );
}
}
///////////////////////////////////////////////////////////////////////////////
// ReadObject -- writes an object from disk, either encrypted or not, that was
// written using WriteObject above.
///////////////////////////////////////////////////////////////////////////////
static void ReadObject(const TCHAR* objFileName, iTypedSerializable* pObjHeader, iTypedSerializable& obj, const cFileHeaderID& fhid, const cElGamalSigPublicKey* pPublicKey, bool& bEncrypted)
{
cDebug d("ReadObject");
d.TraceDebug(_T("Reading %s from file %s\n"), obj.GetType().AsString(), objFileName);
cFileArchive arch;
arch.OpenRead( objFileName );
ReadObjectFromArchive(arch, objFileName, pObjHeader, obj, fhid, pPublicKey, bEncrypted);
}
///////////////////////////////////////////////////////////////////////////////
// IsObjectEncrypted
///////////////////////////////////////////////////////////////////////////////
bool cTWUtil::IsObjectEncrypted( const TCHAR* objFileName, const cFileHeaderID& fhid, const TSTRING& errorMsg )
{
bool fEncrypted = false;
cDebug d("IsObjectEncrypted");
d.TraceDebug(_T("Reading from file %s\n"), objFileName);
try
{
cFileArchive arch;
arch.OpenRead( objFileName );
cFileHeader fileHeader;
cSerializerImpl fhSer(arch, cSerializerImpl::S_READ, objFileName);
fileHeader.Read(&fhSer);
// check for a mismatched header
if (fileHeader.GetID() != fhid)
ThrowAndAssert(eSerializerInputStreamFmt(_T(""), objFileName, eSerializer::TY_FILE));
// switch on the type of encoding...
if(fileHeader.GetEncoding() == cFileHeader::ASYM_ENCRYPTION)
{
fEncrypted = true;
}
else if(fileHeader.GetEncoding() == cFileHeader::COMPRESSED)
{
fEncrypted = false;
}
else
// unknown encoding...
ThrowAndAssert(eSerializerInputStreamFmt(_T(""), objFileName, eSerializer::TY_FILE));
}
catch(eArchive& e)
{
// Note: Output to TCERR is O.K. here, it is documented that this is what this function does
TSTRING msg = e.GetMsg();
if( ! msg.empty() )
msg += _T("\n");
msg += errorMsg;
cTWUtil::PrintErrorMsg(ePoly(e.GetID(), msg, e.GetFlags() ));
ThrowAndAssert(ePoly());
}
catch(eSerializer& e)
{
// Note: Output to TCERR is O.K. here, it is documented that this is what this function does
TSTRING msg = e.GetMsg();
if( ! msg.empty() )
msg += _T("\n");
msg += errorMsg;
cTWUtil::PrintErrorMsg(ePoly(e.GetID(), msg, e.GetFlags() ));
ThrowAndAssert(ePoly());
}
return( fEncrypted );
}
bool cTWUtil::IsObjectEncrypted( cArchive &arch, const cFileHeaderID& fhid, const TSTRING& errorMsg )
{
bool fEncrypted = false;
cDebug d("IsObjectEncrypted");
d.TraceDebug(_T("Reading from archive\n"));
try
{
cFileHeader fileHeader;
cSerializerImpl fhSer(arch, cSerializerImpl::S_READ, TSS_GetString( cTW, tw::STR_MEMORY_MAPPED_FILENAME).c_str());
fileHeader.Read(&fhSer);
// check for a mismatched header
if (fileHeader.GetID() != fhid)
ThrowAndAssert(eSerializerInputStreamFmt(_T(""), TSS_GetString( cTW, tw::STR_MEMORY_MAPPED_FILENAME).c_str(), eSerializer::TY_FILE));
// switch on the type of encoding...
if(fileHeader.GetEncoding() == cFileHeader::ASYM_ENCRYPTION)
{
fEncrypted = true;
}
else if(fileHeader.GetEncoding() == cFileHeader::COMPRESSED)
{
fEncrypted = false;
}
else
// unknown encoding...
ThrowAndAssert(eSerializerInputStreamFmt(_T(""), TSS_GetString( cTW, tw::STR_MEMORY_MAPPED_FILENAME).c_str(), eSerializer::TY_FILE));
}
catch(eArchive& e)
{
// Note: Output to TCERR is O.K. here, it is documented that this is what this function does
TSTRING msg = e.GetMsg();
if( ! msg.empty() )
msg += _T("\n");
msg += errorMsg;
cTWUtil::PrintErrorMsg(ePoly(e.GetID(), msg, e.GetFlags() ));
ThrowAndAssert(ePoly());
}
catch(eSerializer& e)
{
// Note: Output to TCERR is O.K. here, it is documented that this is what this function does
TSTRING msg = e.GetMsg();
if( ! msg.empty() )
msg += _T("\n");
msg += errorMsg;
cTWUtil::PrintErrorMsg(ePoly(e.GetID(), msg, e.GetFlags() ));
ThrowAndAssert(ePoly());
}
return( fEncrypted );
}
///////////////////////////////////////////////////////////////////////////////
// WriteDatabase
///////////////////////////////////////////////////////////////////////////////
void cTWUtil::WriteDatabase(const TCHAR* filename, cFCODatabaseFile& db, bool bEncrypt, const cElGamalSigPrivateKey* pPrivateKey)
{
cFileHeader fileHeader;
fileHeader.SetID(db.GetFileHeaderID());
// I am almost positive that this does nothing, WriteObject() sets the version in the cFileHeader - Jun 8, 1999 - dmb
//fileHeader.SetVersion(1);
#ifdef TW_PROFILE
cWin32TaskTimer timer(_T("Write Database"));
timer.Start();
#endif
WriteObject(filename, 0, db, fileHeader, bEncrypt, pPrivateKey);
#ifdef TW_PROFILE
timer.Stop();
#endif
iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, _T("%s%s\n"),
TSS_GetString( cTW, tw::STR_WRITE_DB_FILE).c_str(),
cDisplayEncoder::EncodeInline( filename ).c_str() );
}
///////////////////////////////////////////////////////////////////////////////
// ReadDatabase
///////////////////////////////////////////////////////////////////////////////
void cTWUtil::ReadDatabase(const TCHAR* filename, cFCODatabaseFile& db, const cElGamalSigPublicKey* pPublicKey, bool& bEncrypted)
{
iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, _T("%s%s\n"),
TSS_GetString( cTW, tw::STR_OPEN_DB_FILE).c_str(),
cDisplayEncoder::EncodeInline( filename ).c_str() );
#ifdef TW_PROFILE
cWin32TaskTimer timer("cTWUtil::ReadDatabase");
timer.Start();
#endif
ReadObject(filename, 0, db, cFCODatabaseFile::GetFileHeaderID(), pPublicKey, bEncrypted);
#ifdef TW_PROFILE
timer.Stop();
#endif
}
///////////////////////////////////////////////////////////////////////////////
// WriteReport
///////////////////////////////////////////////////////////////////////////////
void cTWUtil::WriteReport(const TCHAR* filename, const cFCOReportHeader& reportHeader, const cFCOReport& r, bool bEncrypt, const cElGamalSigPrivateKey* pPrivateKey)
{
cFileHeader fileHeader;
fileHeader.SetID(cFCOReport::GetFileHeaderID());
WriteObject(filename, &reportHeader, r, fileHeader, bEncrypt, pPrivateKey);
iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, _T("%s%s\n"),
TSS_GetString( cTW, tw::STR_WRITE_REPORT_FILE).c_str(),
cDisplayEncoder::EncodeInline( filename ).c_str() );
}
void cTWUtil::WriteReport(cArchive &archive, const cFCOReportHeader& reportHeader, const cFCOReport& r, bool bEncrypt, const cElGamalSigPrivateKey* pPrivateKey)
{
cFileHeader fileHeader;
fileHeader.SetID(cFCOReport::GetFileHeaderID());
TSTRING filename = TSS_GetString( cTW, tw::STR_MEMORY_MAPPED_FILENAME);
WriteObjectToArchive(archive, filename.c_str(), &reportHeader, r, fileHeader, bEncrypt, pPrivateKey);
iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, _T("%s%s\n"),
TSS_GetString( cTW, tw::STR_WRITE_REPORT_FILE).c_str(),
cDisplayEncoder::EncodeInline( filename ).c_str() );
}
///////////////////////////////////////////////////////////////////////////////
// ReadReport
///////////////////////////////////////////////////////////////////////////////
void cTWUtil::ReadReport(const TCHAR* reportFileName, cFCOReportHeader& reportHeader, cFCOReport& r, const cElGamalSigPublicKey* pPublicKey, bool silent, bool& bEncrypted)
{
iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, _T("%s%s\n"),
TSS_GetString( cTW, tw::STR_OPEN_REPORT_FILE).c_str(),
cDisplayEncoder::EncodeInline( reportFileName ).c_str() );
ReadObject(reportFileName, &reportHeader, r, cFCOReport::GetFileHeaderID(), pPublicKey, bEncrypted);
}
void cTWUtil::ReadReport(cArchive &archive, cFCOReportHeader& reportHeader, cFCOReport& r, const cElGamalSigPublicKey* pPublicKey, bool silent, bool& bEncrypted)
{
TSTRING filename = TSS_GetString( cTW, tw::STR_MEMORY_MAPPED_FILENAME);
iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, _T("%s%s\n"),
TSS_GetString( cTW, tw::STR_OPEN_REPORT_FILE).c_str(),
cDisplayEncoder::EncodeInline( filename ).c_str());
ReadObjectFromArchive(archive, filename.c_str(), &reportHeader, r, cFCOReport::GetFileHeaderID(), pPublicKey, bEncrypted);
}
///////////////////////////////////////////////////////////////////////////////
// UpdatePolicyFile
///////////////////////////////////////////////////////////////////////////////
void cTWUtil::UpdatePolicyFile(const TCHAR* destFileName, const TCHAR* srcFileName, bool bEncrypt, const cElGamalSigPrivateKey* pPrivateKey)
{
cFileArchive src;
src.OpenRead(srcFileName); // note: eArchive may float up
std::string policyText;
policyText.resize(src.Length());
src.ReadBlob((void*)policyText.data(), src.Length());
// NOTE -- this method will emit a message to stdout when the file has been written
cTWUtil::WritePolicyText(destFileName, policyText, bEncrypt, pPrivateKey);
}
TSTRING cTWUtil::GetCfgFilePath(const cCmdLineParser& cmdLine, int cfgFileID)
{
TSTRING cfgFilePath;
bool fConfigOnCmdLine = false;
// let's see if this was specified on the command line...
cCmdLineIter iter(cmdLine);
for(iter.SeekBegin(); ! iter.Done(); iter.Next())
{
if(iter.ArgId() == cfgFileID)
{
ASSERT(iter.NumParams() > 0);
cfgFilePath = iter.ParamAt(0);
fConfigOnCmdLine = true;
}
}
// OK, now we need to figure out where to find the config file.
// If the location was specified on the command line, get the full path to it.
// otherwise, the location is the dir that this exe is in.
if( fConfigOnCmdLine )
{
TSTRING pathOut;
iFSServices::GetInstance()->FullPath( pathOut, cfgFilePath ) ;
cfgFilePath = pathOut;
}
else
{
iFSServices::GetInstance()->FullPath( cfgFilePath, TSS_GetString(cTW, tw::STR_DEF_CFG_FILENAME),
cSystemInfo::GetExeDir() ) ;
}
cFileUtil::TestFileExists(cfgFilePath);
return (cfgFilePath);
}
///////////////////////////////////////////////////////////////////////////////
// OpenConfigFile -- opens the config file, either from a known location or
// from the location specified on the command line. Returns false if it fails.
// cfgFileID is the ID of the config file switch
// TODO -- should this guy spit the error to cerr or fill up an error bucket?
/////////////////////////////////////////////////////////////////////////////////
void cTWUtil::OpenConfigFile(cConfigFile& cf, cCmdLineParser& cmdLine, int cfgFileID, cErrorBucket& errorBucket, TSTRING& configFileOut)
{
configFileOut = GetCfgFilePath(cmdLine, cfgFileID);
// ok, now let's load it!
TSTRING configText;
cTWUtil::ReadConfigText(configFileOut.c_str(), configText);
cf.ReadString( configText );
}
///////////////////////////////////////////////////////////////////////////////
// WriteConfigText
// eArchive is thrown if filename can not be opened
// eSerializer is thrown if reading or writing fails
void cTWUtil::WriteConfigText(const TCHAR* filename, const TSTRING configText, bool bEncrypt, const cElGamalSigPrivateKey* pPrivateKey)
{
cSerializableNString nstring;
nstring.mString = CONFIG_FILE_MAGIC_8BYTE;
std::string ns;
cStringUtil::Convert( ns, configText );
nstring.mString += ns;
cFileHeader fileHeader;
fileHeader.SetID(cConfigFile::GetFileHeaderID());
fileHeader.SetVersion(CURRENT_FIXED_VERSION);
if (bEncrypt)
{
ASSERT(pPrivateKey != 0);
cElGamalSigPublicKey publicKey(*pPrivateKey);
fileHeader.GetBaggage().MapArchive(0, publicKey.GetWriteLen());
publicKey.Write(fileHeader.GetBaggage().GetMap());
}
WriteObject(filename, NULL, nstring, fileHeader, bEncrypt, pPrivateKey);
iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, _T("%s%s\n"),
TSS_GetString( cTW, tw::STR_WRITE_CONFIG_FILE).c_str(),
cDisplayEncoder::EncodeInline( filename ).c_str() );
}
void cTWUtil::WriteConfigText(cArchive &archive, const TSTRING configText, bool bEncrypt, const cElGamalSigPrivateKey* pPrivateKey)
{
cSerializableNString nstring;
nstring.mString = CONFIG_FILE_MAGIC_8BYTE;
TSTRING filename = TSS_GetString( cTW, tw::STR_MEMORY_MAPPED_FILENAME);
std::string ns;
cStringUtil::Convert( ns, configText );
nstring.mString += ns;
cFileHeader fileHeader;
fileHeader.SetID(cConfigFile::GetFileHeaderID());
fileHeader.SetVersion(CURRENT_FIXED_VERSION);
if (bEncrypt)
{
ASSERT(pPrivateKey != 0);
cElGamalSigPublicKey publicKey(*pPrivateKey);
fileHeader.GetBaggage().MapArchive(0, publicKey.GetWriteLen());
publicKey.Write(fileHeader.GetBaggage().GetMap());
}
WriteObjectToArchive(archive, filename.c_str(), NULL, nstring, fileHeader, bEncrypt, pPrivateKey);
iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, _T("%s%s\n"),
TSS_GetString( cTW, tw::STR_WRITE_CONFIG_FILE).c_str(),
cDisplayEncoder::EncodeInline( filename ).c_str());
}
///////////////////////////////////////////////////////////////////////////////
// ReadConfigText
// eArchive is thrown if filename can not be opened
// eSerializer is thrown if reading or writing fails
// eConfigFile is thrown if config file does not parse correctly during reading
void cTWUtil::ReadConfigText(const TCHAR* filename, TSTRING& configText, cArchive* pBaggage)
{
// TODO -- neat up this function; try to use LoadObject() above...
cSerializableNString nstring;
// This was coppied from ReadObject(). We need to use the baggage of the
// file header to obtain the public key, thus the special casing.
cDebug d("ReadConfigText");
d.TraceDebug(_T("Reading %s from file %s\n"), nstring.GetType().AsString(), filename);
iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, _T("%s%s\n"),
TSS_GetString( cTW, tw::STR_OPEN_CONFIG_FILE).c_str(),
cDisplayEncoder::EncodeInline( filename ).c_str() );
cFileArchive arch;
arch.OpenRead( filename );
cFileHeader fileHeader;
try
{
cSerializerImpl fhSer(arch, cSerializerImpl::S_READ);
fileHeader.Read(&fhSer);
}
catch (eError&)
{
throw eSerializerInputStreamFmt(_T(""), filename, eSerializer::TY_FILE);
}
#if 0 // XXX: This is broken, what the h*ll are they trying to write here? -PH
d.TraceDebug("Found a file header of type %d.\n", fileHeader.GetEncoding());
#endif
// check for a mismatched header
if (fileHeader.GetID() != cConfigFile::GetFileHeaderID())
throw eSerializerInputStreamFmt(_T(""), filename, eSerializer::TY_FILE);
// check the version
if (fileHeader.GetVersion() != CURRENT_FIXED_VERSION)
throw eSerializerVersionMismatch(_T(""), filename, eSerializer::TY_FILE);
// switch on the type of encoding...
if(fileHeader.GetEncoding() == cFileHeader::ASYM_ENCRYPTION)
{
d.TraceDebug("Config file is compressed, public key len %d.\n", fileHeader.GetBaggage().Length());
// tell the user the db is encrypted
iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, TSS_GetString(cTW, tw::STR_FILE_ENCRYPTED).c_str());
iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, TSS_GetString(cTW, tw::STR_NEWLINE).c_str());
ASSERT(fileHeader.GetBaggage().Length() > 0);
if (fileHeader.GetBaggage().Length() <= 0)
ThrowAndAssert(eSerializerInputStreamFmt(_T(""), filename, eSerializer::TY_FILE));
fileHeader.GetBaggage().MapArchive(0, fileHeader.GetBaggage().Length());
cElGamalSigPublicKey publicKey(fileHeader.GetBaggage().GetMap());
cElGamalSigArchive cryptoArchive;
cryptoArchive.SetRead(&arch, &publicKey);
cSerializerImpl ser(cryptoArchive, cSerializerImpl::S_READ);
ser.Init();
ser.ReadObject(&nstring);
ser.Finit();
// copy the baggage into the archive, if it was passed in
// Note: We rely in VerifySiteKey that we only fill out pBaggage if
// the config file is encrypted.
//
if( pBaggage )
{
fileHeader.GetBaggage().Seek( 0, cBidirArchive::BEGINNING );
pBaggage->Copy( &fileHeader.GetBaggage(), fileHeader.GetBaggage().Length() );
}
}
else if(fileHeader.GetEncoding() == cFileHeader::COMPRESSED)
{
d.TraceDebug("Config file is not compressed.\n");
//not encrypted db...
cNullCryptoArchive cryptoArchive;
cryptoArchive.Start(&arch);
cSerializerImpl ser(cryptoArchive, cSerializerImpl::S_READ);
ser.Init();
ser.ReadObject(&nstring);
ser.Finit();
}
else
// unknown encoding...
throw eSerializerInputStreamFmt(_T(""), filename, eSerializer::TY_FILE);
// check 8 byte header
if (nstring.mString.compare(0, 8*sizeof(byte), CONFIG_FILE_MAGIC_8BYTE) != 0)
ThrowAndAssert(eSerializerInputStreamFmt(_T(""), filename, eSerializer::TY_FILE));
// remove 8 byte header
nstring.mString.assign(nstring.mString.substr(8));
cStringUtil::Convert( configText, nstring.mString );
}
void cTWUtil::ReadConfigText(cArchive &arch, TSTRING& configText, cArchive* pBaggage)
{
// TODO -- neat up this function; try to use LoadObject() above...
cSerializableNString nstring;
TSTRING filename = TSS_GetString( cTW, tw::STR_MEMORY_MAPPED_FILENAME);
// This was coppied from ReadObject(). We need to use the baggage of the
// file header to obtain the public key, thus the special casing.
cDebug d("ReadConfigText");
d.TraceDebug(_T("Reading %s from file %s\n"), nstring.GetType().AsString(), filename.c_str());
iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, _T("%s%s\n"),
TSS_GetString( cTW, tw::STR_OPEN_CONFIG_FILE).c_str(),
cDisplayEncoder::EncodeInline( filename ).c_str());
cFileHeader fileHeader;
try
{
cSerializerImpl fhSer(arch, cSerializerImpl::S_READ);
fileHeader.Read(&fhSer);
}
catch (eError&)
{
throw eSerializerInputStreamFmt(_T(""), filename.c_str(), eSerializer::TY_FILE);
}
#if 0 // XXX: This is broken, how can you convert a class to an int??? -PH
d.TraceDebug("Found a file header of type %d.\n", fileHeader.GetEncoding());
#endif
// check for a mismatched header
if (fileHeader.GetID() != cConfigFile::GetFileHeaderID())
throw eSerializerInputStreamFmt(_T(""), filename.c_str(), eSerializer::TY_FILE);
// check the version
if (fileHeader.GetVersion() != CURRENT_FIXED_VERSION)
throw eSerializerVersionMismatch(_T(""), filename.c_str(), eSerializer::TY_FILE);
// switch on the type of encoding...
if(fileHeader.GetEncoding() == cFileHeader::ASYM_ENCRYPTION)
{
d.TraceDebug("Config file is compressed, public key len %d.\n", fileHeader.GetBaggage().Length());
// tell the user the db is encrypted
iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, TSS_GetString(cTW, tw::STR_FILE_ENCRYPTED).c_str());
iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, TSS_GetString(cTW, tw::STR_NEWLINE).c_str());
ASSERT(fileHeader.GetBaggage().Length() > 0);
if (fileHeader.GetBaggage().Length() <= 0)
ThrowAndAssert(eSerializerInputStreamFmt(_T(""), filename.c_str(), eSerializer::TY_FILE));
fileHeader.GetBaggage().MapArchive(0, fileHeader.GetBaggage().Length());
cElGamalSigPublicKey publicKey(fileHeader.GetBaggage().GetMap());
cElGamalSigArchive cryptoArchive;
cryptoArchive.SetRead(&arch, &publicKey);
cSerializerImpl ser(cryptoArchive, cSerializerImpl::S_READ);
ser.Init();
ser.ReadObject(&nstring);
ser.Finit();
// copy the baggage into the archive, if it was passed in
// Note: We rely in VerifySiteKey that we only fill out pBaggage if
// the config file is encrypted.
//
if( pBaggage )
{
fileHeader.GetBaggage().Seek( 0, cBidirArchive::BEGINNING );
pBaggage->Copy( &fileHeader.GetBaggage(), fileHeader.GetBaggage().Length() );
}
}
else if(fileHeader.GetEncoding() == cFileHeader::COMPRESSED)
{
d.TraceDebug("Config file is not compressed.\n");
//not encrypted db...
cNullCryptoArchive cryptoArchive;
cryptoArchive.Start(&arch);
cSerializerImpl ser(cryptoArchive, cSerializerImpl::S_READ);
ser.Init();
ser.ReadObject(&nstring);
ser.Finit();
}
else
// unknown encoding...
throw eSerializerInputStreamFmt(_T(""), filename.c_str(), eSerializer::TY_FILE);
// check 8 byte header
if (nstring.mString.compare(0, 8*sizeof(byte), CONFIG_FILE_MAGIC_8BYTE) != 0)
ThrowAndAssert(eSerializerInputStreamFmt(_T(""), filename.c_str(), eSerializer::TY_FILE));
// remove 8 byte header
nstring.mString.assign(nstring.mString.substr(8));
cStringUtil::Convert( configText, nstring.mString );
}
///////////////////////////////////////////////////////////////////////////////
// Given a filename and the text of a policy file, write an encrypted version
// of the policy file text to disk.
// Will throw eError on failure.
void cTWUtil::WritePolicyText(const TCHAR* filename, const std::string polText, bool bEncrypt, const cElGamalSigPrivateKey* pPrivateKey)
{
cSerializableNString nstring;
// add a 8 byte header we can use to verify decryption
nstring.mString = POLICY_FILE_MAGIC_8BYTE;
nstring.mString += polText;
cFileHeader fileHeader;
fileHeader.SetID(cPolicyFile::GetFileHeaderID());
WriteObject(filename, NULL, nstring, fileHeader, bEncrypt, pPrivateKey);
iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, _T("%s%s\n"),
TSS_GetString( cTW, tw::STR_WRITE_POLICY_FILE).c_str(),
cDisplayEncoder::EncodeInline( filename ).c_str() );
}
void cTWUtil::WritePolicyText(cArchive &archive, const std::string polText, bool bEncrypt, const cElGamalSigPrivateKey* pPrivateKey)
{
cSerializableNString nstring;
TSTRING filename = TSS_GetString( cTW, tw::STR_MEMORY_MAPPED_FILENAME);
// add a 8 byte header we can use to verify decryption
nstring.mString = POLICY_FILE_MAGIC_8BYTE;
nstring.mString += polText;
cFileHeader fileHeader;
fileHeader.SetID(cPolicyFile::GetFileHeaderID());
WriteObjectToArchive(archive, filename.c_str(), NULL, nstring, fileHeader, bEncrypt, pPrivateKey);
iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, _T("%s%s\n"),
TSS_GetString( cTW, tw::STR_WRITE_POLICY_FILE).c_str(),
cDisplayEncoder::EncodeInline( filename ).c_str());
}
///////////////////////////////////////////////////////////////////////////////
// ReadPolicyText
//
// Read the policy file. Read the text of a policy language into configText
// Will throw eError on failure.
///////////////////////////////////////////////////////////////////////////////
void cTWUtil::ReadPolicyText(const TCHAR* filename, std::string& polText, const cElGamalSigPublicKey* pPublicKey)
{
cSerializableNString nstring;
cFileUtil::TestFileExists(filename);
bool bEncrypted;
ReadObject(filename, NULL, nstring, cPolicyFile::GetFileHeaderID(), pPublicKey, bEncrypted);
// check 8 byte header
if (nstring.mString.compare(0, 8*sizeof(byte), POLICY_FILE_MAGIC_8BYTE) != 0)
ThrowAndAssert(eSerializerInputStreamFmt(_T(""), filename, eSerializer::TY_FILE));
// remove 8 byte header
nstring.mString.assign(nstring.mString.substr(8));
polText = nstring.mString;
}
void cTWUtil::ReadPolicyText(cArchive &archive, std::string& polText, const cElGamalSigPublicKey* pPublicKey)
{
cSerializableNString nstring;
TSTRING filename = TSS_GetString( cTW, tw::STR_MEMORY_MAPPED_FILENAME);
bool bEncrypted;
ReadObjectFromArchive(archive, filename.c_str(), NULL, nstring, cPolicyFile::GetFileHeaderID(), pPublicKey, bEncrypted);
// check 8 byte header
if (nstring.mString.compare(0, 8*sizeof(byte), POLICY_FILE_MAGIC_8BYTE) != 0)
ThrowAndAssert(eSerializerInputStreamFmt(_T(""), filename.c_str(), eSerializer::TY_FILE));
// remove 8 byte header
nstring.mString.assign(nstring.mString.substr(8));
polText = nstring.mString;
}
///////////////////////////////////////////////////////////////////////////////
// OpenKeyFile
///////////////////////////////////////////////////////////////////////////////
void cTWUtil::OpenKeyFile(cKeyFile& keyFile, TSTRING fileName)
{
// first, make sure the file exists...
cFileUtil::TestFileExists(fileName);
iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, _T("%s%s\n"),
TSS_GetString( cTW, tw::STR_OPEN_KEYFILE).c_str(),
cDisplayEncoder::EncodeInline( fileName ).c_str());
keyFile.ReadFile(fileName.c_str());
}
///////////////////////////////////////////////////////////////////////////////
// CreatePrivateKey
// we will attempt to get the correct passphrase three times before we
// give up.
///////////////////////////////////////////////////////////////////////////////
const cElGamalSigPrivateKey* cTWUtil::CreatePrivateKey(cKeyFile& keyFile, const WCHAR16* usePassphrase, KeyType keyType, int nSecs)
{
ASSERT(keyType == KEY_SITE || keyType == KEY_LOCAL || keyType == KEY_PROVIDED);
const cElGamalSigPrivateKey* pPrivateKey = NULL;
wc16_string passphrase;
if ( usePassphrase )
{
// sleep to hinder brute force (dictionary, etc.) attacks
iFSServices::GetInstance()->Sleep( nSecs );
passphrase = usePassphrase;
#ifndef WORDS_BIGENDIAN
passphrase.swapbytes();
#endif
pPrivateKey = keyFile.GetPrivateKey((int8*)passphrase.data(), passphrase.length() * sizeof(WCHAR16));
if(pPrivateKey)
return pPrivateKey;
// if we got here, then a passphrase was provided on the command line that
// was not correct; this is an error condition.
//
if( keyType == KEY_LOCAL )
throw eTWUtilBadPassLocal();
else
throw eTWUtilBadPassSite();
}
int count = 0;
while(count < 3)
{
cTWUtil::NoEcho noEcho;
switch (keyType)
{
case KEY_LOCAL:
TCOUT << TSS_GetString( cTW, tw::STR_ENTER_LOCAL_PASSPHRASE);
break;
case KEY_SITE:
TCOUT << TSS_GetString( cTW, tw::STR_ENTER_SITE_PASSPHRASE);
break;
case KEY_PROVIDED:
default:
TCOUT << TSS_GetString( cTW, tw::STR_ENTER_PROVIDED_PASSPHRASE);
break;
}
cTWUtil::GetString(passphrase);
TCOUT << std::endl;
// sleep to hinder brute force (dictionary, etc.) attacks
iFSServices::GetInstance()->Sleep( nSecs );
#ifndef WORDS_BIGENDIAN
passphrase.swapbytes();
#endif
pPrivateKey = keyFile.GetPrivateKey((int8*)passphrase.data(), passphrase.length() * sizeof(WCHAR16));
if (pPrivateKey)
break;
// tell the user that they entered the wrong passphrase
int strId = (keyType==KEY_LOCAL) ? tw::STR_ERR_WRONG_PASSPHRASE_LOCAL :
tw::STR_ERR_WRONG_PASSPHRASE_SITE;
TCOUT << TSS_GetString( cTW, strId) << std::endl;
passphrase.resize(0);
count++;
}
if(! pPrivateKey)
throw ePoly();
return pPrivateKey;
}
void cTWUtil::CreatePrivateKey(cPrivateKeyProxy& proxy, cKeyFile& keyFile, const WCHAR16* usePassphrase, KeyType keyType, int nSecs)
{
ASSERT(keyType == KEY_SITE || keyType == KEY_LOCAL || keyType == KEY_PROVIDED);
wc16_string passphrase;
if (usePassphrase != 0)
{
// sleep to hinder brute force (dictionary, etc.) attacks
iFSServices::GetInstance()->Sleep( nSecs );
passphrase = usePassphrase;
#ifndef WORDS_BIGENDIAN
passphrase.swapbytes();
#endif
if (proxy.AquireKey(keyFile, (int8*)passphrase.data(), passphrase.length() * sizeof(WCHAR16)))
return;
// if we got here, then a passphrase was provided on the command line that
// was not correct; this is an error condition.
//
if( keyType == KEY_LOCAL )
throw eTWUtilBadPassLocal();
else
throw eTWUtilBadPassSite();
}
int count = 0;
while(count < 3)
{
cTWUtil::NoEcho noEcho;
switch (keyType)
{
case KEY_LOCAL:
TCOUT << TSS_GetString( cTW, tw::STR_ENTER_LOCAL_PASSPHRASE);
break;
case KEY_SITE:
TCOUT << TSS_GetString( cTW, tw::STR_ENTER_SITE_PASSPHRASE);
break;
case KEY_PROVIDED:
default:
TCOUT << TSS_GetString( cTW, tw::STR_ENTER_PROVIDED_PASSPHRASE);
break;
}
cTWUtil::GetString(passphrase);
TCOUT << std::endl;
// sleep to hinder brute force (dictionary, etc.) attacks
iFSServices::GetInstance()->Sleep( nSecs );
#ifndef WORDS_BIGENDIAN
passphrase.swapbytes();
#endif
if (proxy.AquireKey(keyFile, (int8*)passphrase.data(), passphrase.length() * sizeof(WCHAR16)))
return;
// tell the user that they entered the wrong passphrase
int strId = (keyType==KEY_LOCAL) ? tw::STR_ERR_WRONG_PASSPHRASE_LOCAL :
(keyType==KEY_SITE) ? tw::STR_ERR_WRONG_PASSPHRASE_SITE :
tw::STR_ERR_WRONG_PASSPHRASE_LOCAL; // TODO: make this provided
TCOUT << TSS_GetString( cTW, strId) << std::endl;
passphrase.resize(0);
count++;
}
throw ePoly();
}
///////////////////////////////////////////////////////////////////////////////
// GetStringNoEcho -- Get a string from the user without echoing it
///////////////////////////////////////////////////////////////////////////////
#if IS_UNIX
static void (*old_SIGINT)(int);
static void (*old_SIGQUIT)(int);
static struct termios Otty;
static void RestoreEcho(int sig)
{
#ifdef _DEBUG
std::cout << "Caught signal, resetting echo."<< std::endl;
sleep(2);
#endif
tcsetattr( 0, TCSAFLUSH, &Otty);
tw_signal(SIGINT, old_SIGINT);
tw_signal(SIGQUIT, old_SIGQUIT);
tw_raise(sig);
}
void cTWUtil::GetString(wc16_string& ret)
{
#ifdef _UNICODE
#error We depend on Unix not being Unicode
#endif
// get the string
const int MAX_STRING = 1024;
char buf[MAX_STRING];
int len;
TCOUT.flush();
len = read( 0, buf, MAX_STRING );
// TODO:BAM -- mb-enable this!
if (len < MAX_STRING - 1)
buf[len] = 0;
char* psz = tss::strdec( buf, buf + len );
if ( *psz == '\n')
*psz = 0;
ret = cStringUtil::TstrToWstr( buf );
}
cTWUtil::NoEcho::NoEcho()
{
// set the terminal to no echo mode
static struct termios Ntty;
fflush(stdout);
tcgetattr( 0, &Otty);
Ntty = Otty;
Ntty.c_lflag &= ~ECHO;
// catch SIGINT and SIGQUIT
old_SIGINT = tw_signal(SIGINT, RestoreEcho);
old_SIGQUIT = tw_signal(SIGQUIT, RestoreEcho);
if (tcsetattr( 0, TCSAFLUSH, &Ntty) != 0 && isatty(0))
{
ThrowAndAssert(eTWUtilEchoModeSet());
}
}
cTWUtil::NoEcho::~NoEcho() {
tcsetattr( 0, TCSAFLUSH, &Otty);
tw_signal(SIGINT, old_SIGINT);
tw_signal(SIGQUIT, old_SIGQUIT);
}
void cTWUtil::GetStringNoEcho(wc16_string& ret)
{
NoEcho noEcho;
GetString(ret);
}
#endif
///////////////////////////////////////////////////////////////////////////////
// ParseObjectList
///////////////////////////////////////////////////////////////////////////////
void cTWUtil::ParseObjectList( cTWUtil::GenreObjList& listOut, const cTWUtil::ObjList& listIn )
{
cGenre::Genre curGenre = cGenreSwitcher::GetInstance()->GetDefaultGenre();
ASSERT( listIn.size() > 0 );
listOut.clear();
GenreObjList::iterator curIter = listOut.end();
cGenre::Genre iterGenre = cGenre::GENRE_INVALID;
// iterate over all of the input...
//
for( ObjList::const_iterator i = listIn.begin(); i != listIn.end(); i++ )
{
// first, try to interperate the current string as a genre name...
// 17 Mar 99 mdb -- we now only do this if the string ends in a ':'
//
cGenre::Genre g = cGenre::GENRE_INVALID;
if( i->at( i->length()-1 ) == _T(':') )
{
TSTRING genreStr;
genreStr.assign( i->begin(), i->end()-1 );
g = cGenreSwitcher::GetInstance()->StringToGenre( genreStr.c_str() );
//
// if it is not a valid genre name, then test to see if it could
// be an fconame. If it is not, then it is a badly formed genre.
//
if( g == cGenre::GENRE_INVALID )
{
std::auto_ptr<iParserGenreUtil> pParseUtil (iTWFactory::GetInstance()->CreateParserGenreUtil());
if( ! pParseUtil->IsAbsolutePath( *i ) )
throw eTWUnknownSectionName( *i );
}
}
if( g == cGenre::GENRE_INVALID )
{
// assume that we are in the correct genre; this is a fully qualified object name
// TODO -- throw here if cGenreParserHelper says it isn't a fully qualified name.
//
if( iterGenre != curGenre )
{
// seek to right list; create it if it is not there...
//
for( curIter = listOut.begin(); curIter != listOut.end(); curIter++ )
{
if( curIter->first == curGenre )
break;
}
if( curIter == listOut.end() )
{
// it doesn't exist; we will have to create a new one.
//
listOut.push_back( GenreObjs() );
listOut.back().first = curGenre;
curIter = listOut.end() - 1;
}
iterGenre = curGenre;
}
ASSERT( curIter != listOut.end() );
//
// add this to the list; assert that it has not been added yet.
//
ObjList::iterator oi;
for( oi = curIter->second.begin(); oi != curIter->second.end(); oi++ )
{
if( *oi == *i )
{
//TODO -- what should I do here? probably warn and continue...
ASSERT( false );
break;
}
}
if( oi == curIter->second.end() )
curIter->second.push_back( *i );
}
else
{
// set the current genre to this and continue...
//
curGenre = g;
}
}
}
///////////////////////////////////////////////////////////////////////////////
// ParseObjectName
///////////////////////////////////////////////////////////////////////////////
cFCOName cTWUtil::ParseObjectName( const TSTRING& fcoName )
{
std::auto_ptr<iParserGenreUtil> pParseUtil (iTWFactory::GetInstance()->CreateParserGenreUtil());
cFCOName name( iTWFactory::GetInstance()->GetNameInfo() );
//
// make sure the fco name is a full path...
//
if( ! pParseUtil->IsAbsolutePath( fcoName ) )
throw eTWUtilNotFullPath( fcoName );
//
// construct the list that InterpretFCOName needs....
std::list<TSTRING> inputNameList;
//
// dice up the string into a list
// currently, we only slice it up based on "|" (for nt registry entries)
//
TSTRING::size_type pos = fcoName.find_first_of( _T('|') );
if( pos != TSTRING::npos )
{
// if the input string is "foo|bar" then we want the list to
// look like this: "foo", "|", "bar" (three entries)
//
TSTRING str;
str.assign( fcoName, 0, pos );
inputNameList.push_back( str );
inputNameList.push_back( _T("|") );
str.assign( fcoName, pos+1, fcoName.length() - pos );
inputNameList.push_back( str );
}
else
{
inputNameList.push_back( fcoName );
}
pParseUtil->InterpretFCOName( inputNameList, name ) ;
return name;
}
///////////////////////////////////////////////////////////////////////////////
// Database and report header helpers
///////////////////////////////////////////////////////////////////////////////
TSTRING cTWUtil::GetSystemName()
{
TSTRING ret;
iFSServices::GetInstance()->GetMachineName(ret);
return ret;
}
TSTRING cTWUtil::GetIPAddress()
{
uint32 ipaddress;
if (iFSServices::GetInstance()->GetIPAddress(ipaddress) == false)
return TSS_GetString( cTW, tw::STR_IP_UNKNOWN);
// convert to host byte-order
ipaddress = tw_ntohl( ipaddress );
TOSTRINGSTREAM ret;
ret << (int)(ipaddress >> 24) << _T(".")
<< (int)((ipaddress >> 16) & 0xff) << _T(".")
<< (int)((ipaddress >> 8) & 0xff) << _T(".")
<< (int)(ipaddress & 0xff);
return ret.str();
}
TSTRING cTWUtil::GetCurrentUser()
{
TSTRING ret;
iFSServices::GetInstance()->GetCurrentUserName(ret);
return ret;
}
TSTRING cTWUtil::GetHostID()
{
TSTRING ret;
iFSServices::GetInstance()->GetHostID(ret);
return ret;
}
///////////////////////////////////////////////////////////////////////////////
// PrintErrorMsg
///////////////////////////////////////////////////////////////////////////////
void cTWUtil::PrintErrorMsg(const eError& e, const TSTRING& strExtra)
{
ASSERT( e.GetID() != 0 ); // NOTE: BAM 5/9/99 -- there should no longer be an ID of ZERO
/* BAM 5/9/99 -- this is old stuff
if((e.GetID() == 0) && (e.GetMsg().empty()))
{
// this should only occur at the top level of a program (ie -- twcmdline.cpp) and
// indicates that an error occurred and an error message has already been printed out.
// Therefore, we will do nothing here but return.
return;
}
*/
cErrorReporter::PrintErrorMsg(e, strExtra);
}
///////////////////////////////////////////////////////////////////////////////
// ConfirmYN(const TCHAR* prompt)
//
// prompt the user with given string and wait for a 'Y' or 'N' response.
// returns true if 'Y' entered.
///////////////////////////////////////////////////////////////////////////////
bool cTWUtil::ConfirmYN(const TCHAR* prompt)
{
wc16_string reply;
TSTRING s;
int x;
while (1)
{
TCOUT << prompt;
GetString(reply);
cStringUtil::Convert(s, reply);
#ifdef UNICODE
for (x = 0; s[x] && iswctype(s[x], wctype("space") ); x++)
;
#else
for (x = 0; s[x] && std::isspace<TCHAR>( s[x], std::locale() ); x++)
;
#endif
if (_totupper(s[x]) == _T('Y'))
return true;
else if (_totupper(s[x]) == _T('N'))
return false;
}
}
///////////////////////////////////////////////////////////////////////////////
// VerifySiteKey
///////////////////////////////////////////////////////////////////////////////
bool cTWUtil::VerifyCfgSiteKey( const TSTRING& strConfigFile, const TSTRING& siteKeyPath )
{
// open the config file
//
cMemoryArchive memArch;
try
{
TSTRING dummyString;
cTWUtil::ReadConfigText( strConfigFile.c_str(), dummyString, &memArch );
}
catch (eArchive& e)
{
// if the file is corrupted, eArchive may be thrown.
// For sanity sake we need to re-throw this as eTWUtil
TSTRING estr;
estr.assign(TSS_GetString( cCore, core::STR_ERROR_FILENAME ));
estr.append(strConfigFile);
estr.append(TSS_GetString( cCore, core::STR_NEWLINE ));
estr.append(e.GetMsg());
throw eTWUtilCorruptedFile( estr );
}
// only do the test if there is baggage (indicating the cfg file is encrypted)
//
ASSERT(memArch.Length() >= 0);
if (memArch.Length() <= 0)
return false;
// get site public key
//
cKeyFile siteKeyfile;
cTWUtil::OpenKeyFile( siteKeyfile, siteKeyPath );
// create the two public keys...
//
memArch.Seek( 0, cBidirArchive::BEGINNING );
cElGamalSigPublicKey pubKey( memArch.GetMemory() );
// compare the two ....
//
if( ! pubKey.IsEqual( *siteKeyfile.GetPublicKey() ) )
{
TSTRING estr;
estr.assign(TSS_GetString( cTW, tw::STR_ERR2_CFG_KEY_MISMATCH1 ));
estr.append(strConfigFile);
estr.append(TSS_GetString( cTW, tw::STR_ERR2_CFG_KEY_MISMATCH2 ));
estr.append(siteKeyPath);
estr.append(TSS_GetString( cTW, tw::STR_ERR2_CFG_KEY_MISMATCH3 ));
throw eTWUtilCfgKeyMismatch( estr );
}
return true;
}