1492 lines
51 KiB
C++
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;
|
|
}
|
|
|
|
|