2807 lines
107 KiB
C++
2807 lines
107 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.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// twcmdline.cpp
|
|
#include "stdtripwire.h"
|
|
#include "twcmdline.h"
|
|
#include "core/cmdlineparser.h"
|
|
#include "tw/configfile.h"
|
|
|
|
#include "core/serializerimpl.h" // cSerializerImpl
|
|
#include "core/archive.h" // cArchive and friends
|
|
#include "fco/fcospeclist.h" // cFCOSpecList
|
|
#include "tripwirestrings.h" // tripwire.exe specific strings
|
|
#include "twcrypto/keyfile.h" // cKeyFile -- used for encryption
|
|
#include "tw/twutil.h"
|
|
#include "twcmdlineutil.h" // utility functions for the cmd line
|
|
#include "tw/fcoreport.h" // for reports
|
|
#include "tw/textreportviewer.h" // text report viewer
|
|
#include "core/usernotify.h" // for notifying the user of events
|
|
#include "tw/fcoreportutil.h" // for finalizing report
|
|
#include "tw/fcodatabaseutil.h" // for finalizing database
|
|
#include "tw/headerinfo.h" // for finalizing database
|
|
#include "fco/fcopropdisplayer.h"
|
|
#include "tw/systeminfo.h"
|
|
#include "tw/filemanipulator.h"
|
|
#include "fco/twfactory.h"
|
|
#include "mailmessage.h" // used for email reporting
|
|
#include "fco/genrespeclist.h"
|
|
#include "core/twlimits.h" // for severity limits
|
|
#include "core/errorgeneral.h"
|
|
#include "core/corestrings.h"
|
|
#include "tw/twerrors.h"
|
|
#include "core/stringutil.h"
|
|
#include "util/fileutil.h"
|
|
#include "tw/twstrings.h"
|
|
#include "syslog_trip.h"
|
|
#include <set>
|
|
#include "fco/parsergenreutil.h" // this is needed to figure out if a path is fully qualified for the current genre.
|
|
#include "tw/fcodatabasefile.h"
|
|
#include "fco/genreswitcher.h"
|
|
#include "generatedb.h"
|
|
#include "integritycheck.h"
|
|
#include "updatedb.h"
|
|
#include "policyupdate.h"
|
|
|
|
#ifdef TW_PROFILE
|
|
#include "tasktimer.h"
|
|
#endif
|
|
|
|
#if IS_UNIX
|
|
#include "fs/fsdatasourceiter.h" // for cross file systems flag
|
|
#include <unistd.h> // for _exit()
|
|
#endif
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// #defines
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// this is used to make required condition checking in the Init() functions a little more compact
|
|
#define TEST_INIT_REQUIREMENT(t, c, n)\
|
|
if(! t)\
|
|
{\
|
|
cTWUtil::PrintErrorMsg(eTWInitialization(TSS_GetString( c, n ), 0)); \
|
|
return false;\
|
|
}
|
|
|
|
|
|
static bool util_GetEditor( TSTRING& strEd );
|
|
|
|
//#############################################################################
|
|
// cTWCmdLine
|
|
//#############################################################################
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// GetMode -- processes the command line arguments and creates an appropriate
|
|
// structure for the selected mode, or NULL if an error occurs
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
iTWMode* cTWCmdLine::GetMode(int argc, const TCHAR *const * argv)
|
|
{
|
|
// note -- it is assumed the executable name is the first parameter
|
|
if(argc < 2)
|
|
{
|
|
TCOUT << TSS_GetString( cTripwire, tripwire::STR_TRIPWIRE_VERSION) << std::endl;
|
|
TCOUT << TSS_GetString( cTW, tw::STR_VERSION) << std::endl;
|
|
TCOUT << TSS_GetString( cTW, tw::STR_GET_HELP) << std::endl;
|
|
return NULL;
|
|
}
|
|
|
|
int mode = MODE;
|
|
const TCHAR* pcMode;
|
|
if(_tcscmp(argv[1], _T("-m")) == 0)
|
|
{
|
|
if(argc < 3)
|
|
{
|
|
TCOUT << TSS_GetString( cTripwire, tripwire::STR_TRIPWIRE_VERSION) << std::endl;
|
|
TCOUT << TSS_GetString( cTW, tw::STR_VERSION) << std::endl;
|
|
TCOUT << TSS_GetString( cTW, tw::STR_ERR_NO_MODE) << std::endl;
|
|
TCOUT << TSS_GetString( cTW, tw::STR_GET_HELP) << std::endl;
|
|
return NULL;
|
|
}
|
|
pcMode = argv[2];
|
|
if (_tcscmp(argv[2], _T("i")) == 0)
|
|
mode = MODE_INIT;
|
|
else if (_tcscmp(argv[2], _T("c")) == 0)
|
|
mode = MODE_CHECK;
|
|
else if (_tcscmp(argv[2], _T("u")) == 0)
|
|
mode = MODE_UPDATE_DB;
|
|
else if (_tcscmp(argv[2], _T("p")) == 0)
|
|
mode = MODE_UPDATE_POL;
|
|
else if (_tcscmp(argv[2], _T("t")) == 0)
|
|
mode = MODE_TEST;
|
|
}
|
|
else
|
|
{
|
|
pcMode = argv[1];
|
|
if (_tcscmp(argv[1], _T("--init")) == 0)
|
|
mode = MODE_INIT;
|
|
else if (_tcscmp(argv[1], _T("--check")) == 0)
|
|
mode = MODE_CHECK;
|
|
else if (_tcscmp(argv[1], _T("--update")) == 0)
|
|
mode = MODE_UPDATE_DB;
|
|
else if (_tcscmp(argv[1], _T("--update-policy")) == 0)
|
|
mode = MODE_UPDATE_POL;
|
|
else if (_tcscmp(argv[1], _T("--version")) == 0)
|
|
mode = MODE_VERSION;
|
|
else if (_tcscmp(argv[1], _T("--help")) == 0 || _tcscmp(argv[1], _T("-?")) == 0)
|
|
mode = MODE_HELP;
|
|
else if (_tcscmp(argv[1], _T("--test")) == 0)
|
|
mode = MODE_TEST;
|
|
|
|
#ifdef _DEBUG_DB
|
|
if (_tcscmp(argv[1], _T("--explore")) == 0)
|
|
mode = MODE_EXPLORE;
|
|
if (_tcscmp(argv[1], _T("--verifydb")) == 0)
|
|
mode = MODE_DEBUG;
|
|
#endif
|
|
|
|
}
|
|
|
|
if(mode == MODE)
|
|
{
|
|
// unknown mode switch
|
|
cDebug d("cTWCmdLine::GetMode");
|
|
d.TraceError(_T("Error: Bad mode switch: %s\n"), pcMode);
|
|
TCERR << TSS_GetString( cTW, tw::STR_UNKOWN_MODE_SPECIFIED)
|
|
<< pcMode << std::endl
|
|
<< TSS_GetString( cTW, tw::STR_GET_HELP) << std::endl;
|
|
return NULL;
|
|
}
|
|
|
|
|
|
iTWMode* pRtn = 0;
|
|
switch(mode)
|
|
{
|
|
case cTWCmdLine::MODE_INIT:
|
|
pRtn = new cTWModeDbInit;
|
|
break;
|
|
case cTWCmdLine::MODE_CHECK:
|
|
pRtn = new cTWModeIC;
|
|
break;
|
|
case cTWCmdLine::MODE_UPDATE_DB:
|
|
pRtn = new cTWModeDbUpdate;
|
|
break;
|
|
case cTWCmdLine::MODE_UPDATE_POL:
|
|
pRtn = new cTWModePolUpdate;
|
|
break;
|
|
case cTWCmdLine::MODE_TEST:
|
|
pRtn = new cTWModeTest;
|
|
break;
|
|
case cTWCmdLine::MODE_HELP:
|
|
pRtn = new cTWModeHelp;
|
|
break;
|
|
case cTWCmdLine::MODE_VERSION:
|
|
pRtn = new cTWModeVersion;
|
|
break;
|
|
|
|
//Explore and Debug modes are invisible unless _DEBUG_DB is defined.
|
|
#ifdef _DEBUG_DB
|
|
case cTWCmdLine::MODE_EXPLORE:
|
|
pRtn = new cTWModeExploreDb;
|
|
break;
|
|
case cTWCmdLine::MODE_DEBUG:
|
|
pRtn = new cTWModeDebugDb;
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
ASSERT(false);
|
|
}
|
|
|
|
return pRtn;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// InitCmdLineCommon -- initializes the command line switches common to all
|
|
// modes
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
static void InitCmdLineCommon(cCmdLineParser& parser)
|
|
{
|
|
parser.AddArg(cTWCmdLine::HELP, TSTRING(_T("?")), TSTRING(_T("help")), cCmdLineParser::PARAM_NONE);
|
|
parser.AddArg(cTWCmdLine::MODE, TSTRING(_T("m")), TSTRING(_T("")), cCmdLineParser::PARAM_ONE);
|
|
parser.AddArg(cTWCmdLine::VERBOSE, TSTRING(_T("v")), TSTRING(_T("verbose")), cCmdLineParser::PARAM_NONE);
|
|
parser.AddArg(cTWCmdLine::SILENT, TSTRING(_T("s")), TSTRING(_T("silent")), cCmdLineParser::PARAM_NONE);
|
|
parser.AddArg(cTWCmdLine::SILENT, TSTRING(_T("")), TSTRING(_T("quiet")), cCmdLineParser::PARAM_NONE);
|
|
//parser.AddArg(cTWCmdLine::NO_BACKUP, TSTRING(_T("B")), TSTRING(_T("nobackup")), cCmdLineParser::PARAM_NONE);
|
|
// this was dropped from 1.5 -- mdb
|
|
parser.AddArg(cTWCmdLine::LOCAL_PASSPHRASE, TSTRING(_T("P")), TSTRING(_T("local-passphrase")),cCmdLineParser::PARAM_ONE);
|
|
parser.AddArg(cTWCmdLine::POL_FILE, TSTRING(_T("p")), TSTRING(_T("polfile")), cCmdLineParser::PARAM_ONE);
|
|
parser.AddArg(cTWCmdLine::CFG_FILE, TSTRING(_T("c")), TSTRING(_T("cfgfile")), cCmdLineParser::PARAM_ONE);
|
|
parser.AddArg(cTWCmdLine::SITE_KEY_FILE, TSTRING(_T("S")), TSTRING(_T("site-keyfile")), cCmdLineParser::PARAM_ONE);
|
|
parser.AddArg(cTWCmdLine::LOCAL_KEY_FILE, TSTRING(_T("L")), TSTRING(_T("local-keyfile")), cCmdLineParser::PARAM_ONE);
|
|
parser.AddArg(cTWCmdLine::DB_FILE, TSTRING(_T("d")), TSTRING(_T("dbfile")), cCmdLineParser::PARAM_ONE);
|
|
parser.AddArg(cTWCmdLine::REPORT_FILE, TSTRING(_T("r")), TSTRING(_T("twrfile")), cCmdLineParser::PARAM_ONE);
|
|
|
|
//
|
|
// mutual exclusions
|
|
//
|
|
parser.AddMutEx(cTWCmdLine::VERBOSE, cTWCmdLine::SILENT);
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// FillOutConfigInfo -- fills out all the common info with config file information
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
static void FillOutConfigInfo(cTWModeCommon* pModeInfo, const cConfigFile& cf)
|
|
{
|
|
TSTRING str;
|
|
if(cf.Lookup(TSTRING(_T("POLFILE")), str))
|
|
pModeInfo->mPolFile = str;
|
|
if(cf.Lookup(TSTRING(_T("DBFILE")), str))
|
|
pModeInfo->mDbFile = str;
|
|
if(cf.Lookup(TSTRING(_T("SITEKEYFILE")), str))
|
|
pModeInfo->mSiteKeyFile = str;
|
|
if(cf.Lookup(TSTRING(_T("LOCALKEYFILE")), str))
|
|
pModeInfo->mLocalKeyFile = str;
|
|
if(cf.Lookup(TSTRING(_T("REPORTFILE")), str))
|
|
pModeInfo->mReportFile = str;
|
|
if(cf.Lookup(TSTRING(_T("EDITOR")), str))
|
|
pModeInfo->mEditor = str;
|
|
if(cf.Lookup(TSTRING(_T("LATEPROMPTING")), str))
|
|
{
|
|
if (_tcsicmp(str.c_str(), _T("true")) == 0)
|
|
pModeInfo->mbLatePassphrase = true;
|
|
}
|
|
if(cf.Lookup(TSTRING(_T("RESETACCESSTIME")), str))
|
|
{
|
|
|
|
|
|
#if IS_UNIX
|
|
// We do not support reset access time on Unix, so we issue a warning.
|
|
// This used to be a fatal error, however this prevents
|
|
// cross platform config files.
|
|
cTWUtil::PrintErrorMsg(eTWInvalidConfigFileKey(_T("RESETACCESSTIME"), eError::NON_FATAL));
|
|
#endif
|
|
|
|
}
|
|
if(cf.Lookup(TSTRING(_T("LOOSEDIRECTORYCHECKING")), str))
|
|
{
|
|
if (_tcsicmp(str.c_str(), _T("true")) == 0)
|
|
pModeInfo->mfLooseDirs = true;
|
|
}
|
|
|
|
if (cf.Lookup(TSTRING(_T("TEMPDIRECTORY")), str)) {
|
|
|
|
if (str.length() == 0)
|
|
str = "/tmp/";
|
|
|
|
// make sure we have a trailing slash -- thanks Jarno...
|
|
//
|
|
if (str[_tcslen(str.c_str())-1] != '/') {
|
|
str += '/';
|
|
}
|
|
|
|
// make sure it exists...
|
|
//
|
|
|
|
|
|
#ifdef __AROS__
|
|
str = cArosPath::AsNative(str);
|
|
#endif
|
|
|
|
if (access(str.c_str(), F_OK) != 0) {
|
|
TSTRING errStr = TSS_GetString( cCore, core::STR_BAD_TEMPDIRECTORY );
|
|
TSTRING tmpStr = _T("Directory: ");
|
|
tmpStr += (str + _T("\n"));
|
|
tmpStr += errStr;
|
|
throw eTWInvalidTempDirectory(tmpStr);
|
|
}
|
|
else {
|
|
iFSServices::GetInstance()->SetTempDirName(str);
|
|
}
|
|
|
|
}
|
|
|
|
if (cf.Lookup(TSTRING(_T("GLOBALEMAIL")), str)) {
|
|
|
|
if (str.length() != 0)
|
|
pModeInfo->mGlobalEmail = str;
|
|
}
|
|
|
|
//
|
|
// Set the report-viewing level if one has been specified, use
|
|
// default level otherwise.
|
|
//
|
|
if(cf.Lookup(TSTRING(_T("EMAILREPORTLEVEL")), str))
|
|
{
|
|
if (_tcsicmp(str.c_str(), _T("0")) == 0)
|
|
pModeInfo->mEmailReportLevel = cTextReportViewer::SINGLE_LINE;
|
|
else if (_tcsicmp(str.c_str(), _T("1")) == 0)
|
|
pModeInfo->mEmailReportLevel = cTextReportViewer::PARSEABLE;
|
|
else if (_tcsicmp(str.c_str(), _T("2")) == 0)
|
|
pModeInfo->mEmailReportLevel = cTextReportViewer::SUMMARY_ONLY;
|
|
else if (_tcsicmp(str.c_str(), _T("3")) == 0)
|
|
pModeInfo->mEmailReportLevel = cTextReportViewer::CONCISE_REPORT;
|
|
else if (_tcsicmp(str.c_str(), _T("4")) == 0)
|
|
pModeInfo->mEmailReportLevel = cTextReportViewer::FULL_REPORT;
|
|
else
|
|
{
|
|
// They specified an illegal level, error.
|
|
TSTRING errStr = _T("Invalid Level: ");
|
|
errStr += str;
|
|
throw eTWInvalidReportLevelCfg( errStr );
|
|
}
|
|
}
|
|
else
|
|
// no level was specified in the configuration file, use default.
|
|
pModeInfo->mEmailReportLevel = cTextReportViewer::CONCISE_REPORT;
|
|
|
|
|
|
// Decide what mail method should be used to email reports
|
|
if(cf.Lookup(TSTRING(_T("MAILMETHOD")), str))
|
|
{
|
|
if (_tcsicmp(str.c_str(), _T("SENDMAIL")) == 0)
|
|
pModeInfo->mMailMethod = cMailMessage::MAIL_BY_PIPE;
|
|
else if (_tcsicmp(str.c_str(), _T("MAPI")) == 0)
|
|
pModeInfo->mMailMethod = cMailMessage::MAIL_BY_MAPI; // NT support only
|
|
else if( _tcsicmp( str.c_str(), _T("SMTP") ) == 0 )
|
|
pModeInfo->mMailMethod = cMailMessage::MAIL_BY_SMTP;
|
|
else
|
|
pModeInfo->mMailMethod = cMailMessage::INVALID_METHOD;
|
|
}
|
|
else
|
|
{
|
|
pModeInfo->mMailMethod = cMailMessage::NO_METHOD;
|
|
}
|
|
|
|
// Get the SMTP server
|
|
if(cf.Lookup(TSTRING(_T("SMTPHOST")), str))
|
|
pModeInfo->mSmtpHost = str;
|
|
else
|
|
pModeInfo->mSmtpHost = _T("127.0.0.1"); // this is the default
|
|
|
|
// Get the SMTP port number
|
|
if(cf.Lookup(TSTRING(_T("SMTPPORT")), str))
|
|
{
|
|
int i = _ttoi( str.c_str() );
|
|
if( i < 0 || i > SHRT_MAX )
|
|
throw eTWInvalidPortNumber( str );
|
|
pModeInfo->mSmtpPort = static_cast<unsigned short>( i );
|
|
}
|
|
else
|
|
pModeInfo->mSmtpPort = 25; // this is the default
|
|
|
|
// Get the mail program to use if we're piping our email
|
|
if(cf.Lookup(TSTRING(_T("MAILPROGRAM")), str))
|
|
pModeInfo->mMailProgram = str;
|
|
else
|
|
pModeInfo->mMailProgram.erase(); // MAILPROGRAM is not required to be specified
|
|
|
|
// Get the mail program to use if we're piping our email
|
|
if(cf.Lookup(TSTRING(_T("MAILNOVIOLATIONS")), str))
|
|
{
|
|
if (_tcsicmp(str.c_str(), _T("true")) == 0)
|
|
pModeInfo->mMailNoViolations = true;
|
|
else
|
|
pModeInfo->mMailNoViolations = false;
|
|
}
|
|
else
|
|
pModeInfo->mMailNoViolations = true; // MAILPROGRAM is not required to be specified
|
|
|
|
// SYSLOG reporting
|
|
if(cf.Lookup(TSTRING(_T("SYSLOGREPORTING")), str))
|
|
{
|
|
if (_tcsicmp(str.c_str(), _T("true")) == 0)
|
|
pModeInfo->mbLogToSyslog = true;
|
|
else
|
|
pModeInfo->mbLogToSyslog = false;
|
|
}
|
|
else
|
|
pModeInfo->mbLogToSyslog = false;
|
|
|
|
// Crossing file systems
|
|
if(cf.Lookup(TSTRING(_T("CROSSFILESYSTEMS")), str))
|
|
{
|
|
if (_tcsicmp(str.c_str(), _T("true")) == 0)
|
|
pModeInfo->mbCrossFileSystems = true;
|
|
else
|
|
pModeInfo->mbCrossFileSystems = false;
|
|
}
|
|
|
|
//
|
|
// turn all of the file names into full paths (they're relative to the exe dir)
|
|
//
|
|
TSTRING fullPath;
|
|
if(iFSServices::GetInstance()->FullPath( fullPath, pModeInfo->mPolFile, cSystemInfo::GetExeDir() ))
|
|
pModeInfo->mPolFile = fullPath;
|
|
if(iFSServices::GetInstance()->FullPath( fullPath, pModeInfo->mDbFile, cSystemInfo::GetExeDir() ))
|
|
pModeInfo->mDbFile = fullPath;
|
|
if(iFSServices::GetInstance()->FullPath( fullPath, pModeInfo->mSiteKeyFile, cSystemInfo::GetExeDir() ))
|
|
pModeInfo->mSiteKeyFile = fullPath;
|
|
if(iFSServices::GetInstance()->FullPath( fullPath, pModeInfo->mLocalKeyFile, cSystemInfo::GetExeDir() ))
|
|
pModeInfo->mLocalKeyFile = fullPath;
|
|
if(iFSServices::GetInstance()->FullPath( fullPath, pModeInfo->mReportFile, cSystemInfo::GetExeDir() ))
|
|
pModeInfo->mReportFile = fullPath;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// FillOutCmdLineInfo -- fills out info common to all modes that appears on the
|
|
// command line.
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
static void FillOutCmdLineInfo(cTWModeCommon* pModeInfo, const cCmdLineParser& cmdLine)
|
|
{
|
|
cCmdLineIter iter(cmdLine);
|
|
for(iter.SeekBegin(); ! iter.Done(); iter.Next())
|
|
{
|
|
switch(iter.ArgId())
|
|
{
|
|
case cTWCmdLine::VERBOSE:
|
|
pModeInfo->mVerbosity = 2;
|
|
break;
|
|
case cTWCmdLine::SILENT:
|
|
pModeInfo->mVerbosity = 0;
|
|
break;
|
|
case cTWCmdLine::POL_FILE:
|
|
ASSERT(iter.NumParams() > 0); // should be caught by cmd line parser
|
|
pModeInfo->mPolFile = iter.ParamAt(0);
|
|
break;
|
|
case cTWCmdLine::SITE_KEY_FILE:
|
|
ASSERT(iter.NumParams() > 0); // should be caught by cmd line parser
|
|
pModeInfo->mSiteKeyFile = iter.ParamAt(0);
|
|
break;
|
|
case cTWCmdLine::LOCAL_KEY_FILE:
|
|
ASSERT(iter.NumParams() > 0); // should be caught by cmd line parser
|
|
pModeInfo->mLocalKeyFile = iter.ParamAt(0);
|
|
break;
|
|
case cTWCmdLine::DB_FILE:
|
|
ASSERT(iter.NumParams() > 0); // should be caught by cmd line parser
|
|
pModeInfo->mDbFile = iter.ParamAt(0);
|
|
break;
|
|
case cTWCmdLine::REPORT_FILE:
|
|
ASSERT(iter.NumParams() > 0); // should be caught by cmd line parser
|
|
pModeInfo->mReportFile = iter.ParamAt(0);
|
|
break;
|
|
case cTWCmdLine::LOCAL_PASSPHRASE:
|
|
{
|
|
ASSERT(iter.NumParams() > 0); // should be caught by cmd line parser
|
|
pModeInfo->mLocalPassphrase = cStringUtil::TstrToWstr(iter.ParamAt(0));
|
|
pModeInfo->mLocalProvided = true;
|
|
}
|
|
break;
|
|
/* case cTWCmdLine::NO_BACKUP:
|
|
pModeInfo->mbBackup = false;
|
|
break;
|
|
*/ }
|
|
}
|
|
|
|
//
|
|
// turn all of the file names into full paths for nice presentation to the user.
|
|
//
|
|
TSTRING fullPath;
|
|
if(iFSServices::GetInstance()->FullPath(fullPath, pModeInfo->mPolFile))
|
|
pModeInfo->mPolFile = fullPath;
|
|
if(iFSServices::GetInstance()->FullPath(fullPath, pModeInfo->mSiteKeyFile))
|
|
pModeInfo->mSiteKeyFile = fullPath;
|
|
if(iFSServices::GetInstance()->FullPath(fullPath, pModeInfo->mLocalKeyFile))
|
|
pModeInfo->mLocalKeyFile = fullPath;
|
|
if(iFSServices::GetInstance()->FullPath(fullPath, pModeInfo->mDbFile))
|
|
pModeInfo->mDbFile = fullPath;
|
|
if(iFSServices::GetInstance()->FullPath(fullPath, pModeInfo->mReportFile))
|
|
pModeInfo->mReportFile = fullPath;
|
|
|
|
|
|
// use the verbosity information
|
|
ASSERT((pModeInfo->mVerbosity >= 0) && (pModeInfo->mVerbosity < 3));
|
|
iUserNotify::GetInstance()->SetVerboseLevel(pModeInfo->mVerbosity);
|
|
|
|
// if a passphrase was passed on the command line, then late prompting should
|
|
// be set to false so that wrong passwords are detected immediately
|
|
if( pModeInfo->mLocalProvided && pModeInfo->mbLatePassphrase )
|
|
{
|
|
// TODO -- I don't know if we should display this or not -- mdb
|
|
//iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, TSS_GetString( cTripwire, tripwire::STR_NOTIFY_CHANGE_PROMPT_TIME).c_str() );
|
|
pModeInfo->mbLatePassphrase = false;
|
|
}
|
|
}
|
|
|
|
//#############################################################################
|
|
// cTWModeDbInit
|
|
//#############################################################################
|
|
class cTWModeDbInit_i : public cTWModeCommon
|
|
{
|
|
public:
|
|
bool mbEncryptDb;
|
|
|
|
// ctor can set up some default values
|
|
cTWModeDbInit_i() : cTWModeCommon(), mbEncryptDb(true) {}
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// ctor, dtor
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
cTWModeDbInit::cTWModeDbInit()
|
|
{
|
|
mpData = new cTWModeDbInit_i;
|
|
}
|
|
|
|
cTWModeDbInit::~cTWModeDbInit()
|
|
{
|
|
delete mpData;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// InitCmdLineParser
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void cTWModeDbInit::InitCmdLineParser(cCmdLineParser& cmdLine)
|
|
{
|
|
// initialize the switches common to all modes...
|
|
InitCmdLineCommon(cmdLine);
|
|
|
|
cmdLine.AddArg(cTWCmdLine::MODE_INIT, TSTRING(_T("")), TSTRING(_T("init")), cCmdLineParser::PARAM_NONE);
|
|
cmdLine.AddArg(cTWCmdLine::NO_ENCRYPT, TSTRING(_T("e")), TSTRING(_T("no-encryption")), cCmdLineParser::PARAM_NONE);
|
|
cmdLine.AddArg(cTWCmdLine::PARAMS, TSTRING(_T("")), TSTRING(_T("")), cCmdLineParser::PARAM_NONE);
|
|
|
|
// mutual exclusion...
|
|
cmdLine.AddMutEx(cTWCmdLine::NO_ENCRYPT, cTWCmdLine::LOCAL_PASSPHRASE);
|
|
cmdLine.AddMutEx(cTWCmdLine::NO_ENCRYPT, cTWCmdLine::LOCAL_KEY_FILE);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Init
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool cTWModeDbInit::Init(const cConfigFile& cf, const cCmdLineParser& cmdLine)
|
|
{
|
|
// first, fill out everything with the config file info...
|
|
FillOutConfigInfo(mpData, cf);
|
|
|
|
// now, parse the command line...
|
|
// this takes care of the common stuff...
|
|
FillOutCmdLineInfo(mpData, cmdLine);
|
|
|
|
// now do the stuff specific to this mode...
|
|
cCmdLineIter iter(cmdLine);
|
|
for(iter.SeekBegin(); ! iter.Done(); iter.Next())
|
|
{
|
|
switch(iter.ArgId())
|
|
{
|
|
case cTWCmdLine::NO_ENCRYPT:
|
|
mpData->mbEncryptDb = false;
|
|
break;
|
|
default:
|
|
// should I do anything, or just ignore this?
|
|
;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------
|
|
// I require the following information:
|
|
//
|
|
// * local key file
|
|
// * site key file
|
|
// * policy file
|
|
// * db file
|
|
//-----------------------------------------
|
|
TEST_INIT_REQUIREMENT((! mpData->mLocalKeyFile.empty()), cTW, tw::STR_ERR_MISSING_LOCAL_KEY);
|
|
TEST_INIT_REQUIREMENT((! mpData->mSiteKeyFile.empty()), cTW, tw::STR_ERR_MISSING_SITE_KEY);
|
|
TEST_INIT_REQUIREMENT((! mpData->mPolFile.empty()), cTW, tw::STR_ERR_MISSING_POLICY);
|
|
TEST_INIT_REQUIREMENT((! mpData->mDbFile.empty()), cTW, tw::STR_ERR_MISSING_DB);
|
|
|
|
|
|
// make sure that the config file and site key file are in sync...
|
|
//
|
|
if (cTWUtil::VerifyCfgSiteKey( mstrConfigFile, mpData->mSiteKeyFile ) == false)
|
|
cTWUtil::PrintErrorMsg(eTWCfgUnencrypted(_T(""), eError::NON_FATAL|eError::SUPRESS_THIRD_MSG));
|
|
|
|
#if IS_UNIX
|
|
// Set the cross file systems flag appropriately.
|
|
cFSDataSourceIter::SetFileSystemCrossing(mpData->mbCrossFileSystems);
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Execute
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
int cTWModeDbInit::Execute(cErrorQueue* pQueue)
|
|
{
|
|
cFCODatabaseFile dbFile;
|
|
cFCODatabaseFile::iterator dbIter( dbFile );
|
|
|
|
dbFile.SetFileName( mpData->mDbFile );
|
|
try
|
|
{
|
|
// don't go any further if we won't be able to write to the db file...
|
|
cFileUtil::TestFileWritable(mpData->mDbFile);
|
|
|
|
// open the keyfile for early passphrase...
|
|
cKeyFile keyfile;
|
|
const cElGamalSigPrivateKey* pPrivateKey = 0;
|
|
if(mpData->mbEncryptDb)
|
|
{
|
|
cTWUtil::OpenKeyFile(keyfile, mpData->mLocalKeyFile);
|
|
// open the private key for "early passphrase"
|
|
if(! mpData->mbLatePassphrase)
|
|
pPrivateKey = cTWUtil::CreatePrivateKey(keyfile, mpData->mLocalProvided ? mpData->mLocalPassphrase.c_str() : 0, cTWUtil::KEY_LOCAL);
|
|
}
|
|
|
|
//Parse the policy file
|
|
cGenreSpecListVector genreSpecList;
|
|
cTWCmdLineUtil::ParsePolicyFile(genreSpecList, mpData->mPolFile, mpData->mSiteKeyFile, pQueue);
|
|
|
|
#ifdef TW_PROFILE
|
|
cWin32TaskTimer timer("cTripwire::GenerateDatabase");
|
|
timer.Start();
|
|
#endif
|
|
|
|
iUserNotify::GetInstance()->Notify(1, TSS_GetString( cTripwire, tripwire::STR_GENERATING_DB ).c_str() );
|
|
|
|
uint32 gdbFlags = 0;
|
|
gdbFlags |= ( mpData->mbResetAccessTime ? cGenerateDb::FLAG_ERASE_FOOTPRINTS_GD : 0 );
|
|
|
|
// loop through the genres
|
|
cGenreSpecListVector::iterator genreIter;
|
|
for (genreIter = genreSpecList.begin(); genreIter != genreSpecList.end(); ++genreIter)
|
|
{
|
|
// make this genre the current genre.
|
|
//
|
|
cGenreSwitcher::GetInstance()->SelectGenre( genreIter->GetGenre() );
|
|
|
|
// notify the user
|
|
//
|
|
iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL,
|
|
TSS_GetString( cTripwire, tripwire::STR_PROCESSING_GENRE ).c_str(),
|
|
cGenreSwitcher::GetInstance()->GenreToString( cGenreSwitcher::GetInstance()->CurrentGenre(), true ) );
|
|
|
|
// add an entry to the database for each genre we are parsing
|
|
dbFile.AddGenre( genreIter->GetGenre(), &dbIter );
|
|
|
|
// copy the spec list to the database...
|
|
dbIter.GetSpecList() = genreIter->GetSpecList();
|
|
|
|
// generate the database...
|
|
// TODO -- turn pQueue into an error bucket
|
|
cGenerateDb::Execute( dbIter.GetSpecList(), dbIter.GetDb(), dbIter.GetGenreHeader().GetPropDisplayer(), pQueue, gdbFlags );
|
|
}
|
|
|
|
cFCODatabaseUtil::CalculateHeader(
|
|
dbFile.GetHeader(),
|
|
mpData->mPolFile,
|
|
mstrConfigFile,
|
|
mpData->mDbFile,
|
|
mstrCmdLine,
|
|
cSystemInfo::GetExeStartTime(),
|
|
0
|
|
);
|
|
|
|
#ifdef TW_PROFILE
|
|
timer.Stop();
|
|
#endif
|
|
|
|
// write the db to disk...
|
|
if(mpData->mbEncryptDb)
|
|
{
|
|
// open the key file for late passphrase
|
|
if(! pPrivateKey)
|
|
{
|
|
ASSERT(mpData->mbLatePassphrase);
|
|
pPrivateKey = cTWUtil::CreatePrivateKey(keyfile, mpData->mLocalProvided ? mpData->mLocalPassphrase.c_str() : 0, cTWUtil::KEY_LOCAL);
|
|
}
|
|
|
|
// backup the file we are about to overwrite
|
|
cFileUtil::BackupFile(mpData->mDbFile);
|
|
|
|
cTWUtil::WriteDatabase(mpData->mDbFile.c_str(), dbFile, true, pPrivateKey);
|
|
keyfile.ReleasePrivateKey();
|
|
}
|
|
else
|
|
{
|
|
cFileUtil::BackupFile(mpData->mDbFile); // backup the file we are about to overwrite
|
|
|
|
cTWUtil::WriteDatabase(mpData->mDbFile.c_str(), dbFile, false, NULL); // false means no encryption
|
|
}
|
|
}
|
|
catch(eError& e)
|
|
{
|
|
if (mpData->mbLogToSyslog)
|
|
{
|
|
TSTRING msg = TSS_GetString( cTripwire, tripwire::STR_SYSLOG_INIT_FAIL_MSG );
|
|
msg.append(cErrorTable::GetInstance()->Get( e.GetID() ));
|
|
|
|
cSyslog::Log(TSS_GetString( cTripwire, tripwire::STR_SYSLOG_IDENT ).c_str(), cSyslog::LOG_ERROR, msg.c_str());
|
|
}
|
|
|
|
cTWUtil::PrintErrorMsg(e);
|
|
return 8;
|
|
}
|
|
|
|
// everything went ok; return 0
|
|
iUserNotify::GetInstance()->Notify(1, TSS_GetString( cTripwire, tripwire::STR_INIT_SUCCESS ).c_str() );
|
|
|
|
if (mpData->mbLogToSyslog)
|
|
{
|
|
TSTRING msg = TSS_GetString( cTripwire, tripwire::STR_SYSLOG_INIT_MSG ) + mpData->mDbFile;
|
|
cSyslog::Log(TSS_GetString( cTripwire, tripwire::STR_SYSLOG_IDENT ).c_str(), cSyslog::LOG_SUCCESS, msg.c_str());
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// GetModeUsage
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
TSTRING cTWModeDbInit::GetModeUsage( void )
|
|
{
|
|
return ( TSS_GetString( cTripwire, tripwire::STR_TRIPWIRE_HELP_INIT ) );
|
|
}
|
|
|
|
//#############################################################################
|
|
// cTWModeIC
|
|
//#############################################################################
|
|
class cTWModeIC_i : public cTWModeCommon
|
|
{
|
|
public:
|
|
bool mbUpdate; // launch the editor after integrity checking is done
|
|
bool mbPrintToStdout; // print a text version of the report to stdout?
|
|
bool mbEmail; // email the report to the appropriate parties?
|
|
TSTRING mIgnoreProps; // symbols of properties to ignore
|
|
bool mbEncryptReport; // should the report be encrypted?
|
|
int mSeverityLevel; // only policy rules greater than or equal to the specified level will be checked.
|
|
bool mbTrimBySeverity; // do we use mSeverityLevel to trim the spec list?
|
|
TSTRING mSeverityName; // gets mapped to number, then treated like mSeverityLevel
|
|
TSTRING mRuleName; // only the named rule will be checked
|
|
TSTRING mGenreName; // if not empty, specifies the genre to check
|
|
bool mbAnal; // are we in anal mode? (only valid with mbUpdate == true)
|
|
|
|
#ifdef GMMS
|
|
bool mbGmms; // Send violation reports via gmms?
|
|
TSTRING mGmmsProg; // full path to gmms executable
|
|
TSTRING mGmmsOptions; // additional options for gmms command line
|
|
int mGmmsVerbosity; // level 1 or 2 verbosity?
|
|
#endif
|
|
|
|
//TSTRING mCmdLine; // entire command line
|
|
std::vector<TSTRING> mFilesToCheck;
|
|
|
|
// ctor can set up some default values
|
|
cTWModeIC_i() : cTWModeCommon(), mbUpdate(false), mbPrintToStdout(true), mbEmail(false), mbEncryptReport(false),
|
|
mSeverityLevel(-1), mbTrimBySeverity(false), mbAnal(false)
|
|
#ifdef GMMS
|
|
, mbGmms(false), mGmmsVerbosity(2)
|
|
#endif
|
|
{}
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// ctor, dtor
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
cTWModeIC::cTWModeIC()
|
|
{
|
|
mpData = new cTWModeIC_i;
|
|
}
|
|
|
|
cTWModeIC::~cTWModeIC()
|
|
{
|
|
delete mpData;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// InitCmdLineParser
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void cTWModeIC::InitCmdLineParser(cCmdLineParser& cmdLine)
|
|
{
|
|
// initialize the switches common to all modes...
|
|
InitCmdLineCommon(cmdLine);
|
|
|
|
cmdLine.AddArg(cTWCmdLine::MODE_CHECK, TSTRING(_T("")), TSTRING(_T("check")), cCmdLineParser::PARAM_NONE);
|
|
cmdLine.AddArg(cTWCmdLine::INTER_UPDATE, TSTRING(_T("I")), TSTRING(_T("interactive")), cCmdLineParser::PARAM_NONE);
|
|
cmdLine.AddArg(cTWCmdLine::EDITOR, TSTRING(_T("V")), TSTRING(_T("visual")), cCmdLineParser::PARAM_ONE);
|
|
cmdLine.AddArg(cTWCmdLine::NO_TTY, TSTRING(_T("n")), TSTRING(_T("no-tty-output")), cCmdLineParser::PARAM_NONE);
|
|
cmdLine.AddArg(cTWCmdLine::MAIL_REPORT, TSTRING(_T("M")), TSTRING(_T("email-report")), cCmdLineParser::PARAM_NONE);
|
|
cmdLine.AddArg(cTWCmdLine::IGNORE_PROP, TSTRING(_T("i")), TSTRING(_T("ignore")), cCmdLineParser::PARAM_ONE);
|
|
cmdLine.AddArg(cTWCmdLine::ENCRYPT_REPORT, TSTRING(_T("E")), TSTRING(_T("signed-report")), cCmdLineParser::PARAM_NONE);
|
|
cmdLine.AddArg(cTWCmdLine::SEVERITY_LEVEL, TSTRING(_T("l")), TSTRING(_T("severity")), cCmdLineParser::PARAM_ONE);
|
|
//cmdLine.AddArg(cTWCmdLine::SEVERITY_NAME, TSTRING(_T("V")), TSTRING(_T("severityname")), cCmdLineParser::PARAM_ONE);
|
|
cmdLine.AddArg(cTWCmdLine::RULE_NAME, TSTRING(_T("R")), TSTRING(_T("rule-name")), cCmdLineParser::PARAM_ONE);
|
|
cmdLine.AddArg(cTWCmdLine::GENRE_NAME, TSTRING(_T("x")), TSTRING(_T("section")), cCmdLineParser::PARAM_ONE);
|
|
cmdLine.AddArg(cTWCmdLine::PARAMS, TSTRING(_T("")), TSTRING(_T("")), cCmdLineParser::PARAM_MANY);
|
|
|
|
// multiple levels of reporting
|
|
cmdLine.AddArg(cTWCmdLine::REPORTLEVEL, TSTRING(_T("t")), TSTRING(_T("email-report-level")), cCmdLineParser::PARAM_ONE);
|
|
|
|
#ifdef GMMS
|
|
// gmms command line options
|
|
cmdLine.AddArg(cTWCmdLine::USE_GMMS, TSTRING(_T("g")), TSTRING(_T("gmms")), cCmdLineParser::PARAM_NONE);
|
|
cmdLine.AddArg(cTWCmdLine::GMMS_VERBOSITY, TSTRING(_T("b")), TSTRING(_T("gmms-verbosity")), cCmdLineParser::PARAM_ONE);
|
|
#endif
|
|
|
|
// mutual exclusion...
|
|
// you can't specify any of these 3 things together...
|
|
cmdLine.AddMutEx(cTWCmdLine::SEVERITY_LEVEL, cTWCmdLine::RULE_NAME);
|
|
cmdLine.AddDependency( cTWCmdLine::REPORTLEVEL, cTWCmdLine::MAIL_REPORT );
|
|
// Report error if the user has specified an editor and we're not in interactive update
|
|
// mode: This needs to happen here, so we don't nail someone for having the editor
|
|
// specified in the config. file. We should only be this picky if both parameters are
|
|
// passed on the command line.
|
|
cmdLine.AddDependency( cTWCmdLine::EDITOR, cTWCmdLine::INTER_UPDATE );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Init
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool cTWModeIC::Init(const cConfigFile& cf, const cCmdLineParser& cmdLine)
|
|
{
|
|
// We will use this to access the parsed cmdLine.
|
|
cCmdLineIter iter(cmdLine);
|
|
|
|
#ifdef GMMS
|
|
|
|
// Get path to gmms executable from config file
|
|
TSTRING str;
|
|
if(cf.Lookup(TSTRING(_T("GMMS")), str))
|
|
{
|
|
// Path was specified in the configuration file
|
|
mpData->mGmmsProg = str;
|
|
}
|
|
else
|
|
{
|
|
// Path was not specified in the configuration file, try environment variable
|
|
const TCHAR *gmmsDeploy = _tgetenv(_T("GEOPLEX_DEPLOY"));
|
|
if (gmmsDeploy)
|
|
mpData->mGmmsProg = TSTRING(gmmsDeploy) + _T("/bin/gmms"); // Assign by env.var.
|
|
else
|
|
mpData->mGmmsProg = _T("/home/geoplex/bin/gmms"); // No env.var., Take a wild guess.
|
|
}
|
|
|
|
// Get any additional command line options for running gmms from config file
|
|
if(cf.Lookup(TSTRING(_T("GMMSOPTIONS")), str))
|
|
mpData->mGmmsOptions = str;
|
|
|
|
bool bGmmsSpecified=false, bGmmsVerbositySpecified=false;
|
|
|
|
#endif
|
|
|
|
// First, fill out everything with the config file info...
|
|
FillOutConfigInfo(mpData, cf);
|
|
|
|
// Now, parse the command line...
|
|
// this takes care of the common stuff...
|
|
FillOutCmdLineInfo(mpData, cmdLine);
|
|
|
|
|
|
// now do the stuff specific to this mode..
|
|
|
|
for(iter.SeekBegin(); ! iter.Done(); iter.Next())
|
|
{
|
|
switch(iter.ArgId())
|
|
{
|
|
case cTWCmdLine::INTER_UPDATE:
|
|
mpData->mbUpdate = true;
|
|
break;
|
|
case cTWCmdLine::EDITOR:
|
|
ASSERT(iter.NumParams() > 0);
|
|
mpData->mEditor = iter.ParamAt(0);
|
|
break;
|
|
case cTWCmdLine::NO_TTY:
|
|
mpData->mbPrintToStdout = false;
|
|
break;
|
|
case cTWCmdLine::MAIL_REPORT:
|
|
mpData->mbEmail = true;
|
|
break;
|
|
case cTWCmdLine::IGNORE_PROP:
|
|
ASSERT(iter.NumParams() > 0);
|
|
mpData->mIgnoreProps = iter.ParamAt(0);
|
|
break;
|
|
case cTWCmdLine::ENCRYPT_REPORT:
|
|
mpData->mbEncryptReport = true;
|
|
break;
|
|
case cTWCmdLine::SEVERITY_LEVEL:
|
|
ASSERT(iter.NumParams() > 0);
|
|
if (_istdigit(iter.ParamAt(0).c_str()[0]))
|
|
{
|
|
// interpret severity value
|
|
int iSev;
|
|
cSeverityLimits sl;
|
|
if( ! sl.InterpretInt( iter.ParamAt(0), &iSev ) )
|
|
throw eICBadSevVal( iter.ParamAt(0) );
|
|
|
|
mpData->mSeverityLevel = iSev;
|
|
mpData->mbTrimBySeverity = true;
|
|
}
|
|
else
|
|
{
|
|
mpData->mSeverityName = iter.ParamAt(0);
|
|
}
|
|
break;
|
|
case cTWCmdLine::REPORTLEVEL:
|
|
{
|
|
if ( iter.ParamAt(0) == _T("0"))
|
|
mpData->mEmailReportLevel = cTextReportViewer::SINGLE_LINE;
|
|
else if( iter.ParamAt(0) == _T("1") )
|
|
mpData->mEmailReportLevel = cTextReportViewer::PARSEABLE;
|
|
else if( iter.ParamAt(0) == _T("2") )
|
|
mpData->mEmailReportLevel = cTextReportViewer::SUMMARY_ONLY;
|
|
else if( iter.ParamAt(0) == _T("3") )
|
|
mpData->mEmailReportLevel = cTextReportViewer::CONCISE_REPORT;
|
|
else if( iter.ParamAt(0) == _T("4") )
|
|
mpData->mEmailReportLevel = cTextReportViewer::FULL_REPORT;
|
|
else
|
|
{
|
|
// They specified an illegal level, error.
|
|
TSTRING errStr = _T("Invalid Level: ");
|
|
errStr += iter.ParamAt(0);
|
|
throw eTWInvalidReportLevel( errStr );
|
|
}
|
|
}
|
|
//done with report-level stuff.
|
|
break;
|
|
case cTWCmdLine::RULE_NAME:
|
|
ASSERT(iter.NumParams() > 0);
|
|
mpData->mRuleName = iter.ParamAt(0);
|
|
break;
|
|
case cTWCmdLine::GENRE_NAME:
|
|
ASSERT(iter.NumParams() > 0);
|
|
mpData->mGenreName = iter.ParamAt(0);
|
|
break;
|
|
case cTWCmdLine::PARAMS:
|
|
{
|
|
// pack all of these onto the files to check list...
|
|
mpData->mFilesToCheck.clear();
|
|
for(int i=0; i < iter.NumParams(); i++)
|
|
{
|
|
mpData->mFilesToCheck.push_back(iter.ParamAt(i));
|
|
}
|
|
}
|
|
#ifdef GMMS
|
|
case cTWCmdLine::USE_GMMS:
|
|
mpData->mbGmms = true;
|
|
bGmmsSpecified = true;
|
|
break;
|
|
case cTWCmdLine::GMMS_VERBOSITY:
|
|
{
|
|
const TCHAR* psz = iter.ParamAt(0).c_str();
|
|
if ( psz != 0 )
|
|
while ( _istdigit( *psz ) ) ++psz;
|
|
|
|
/// NOTE:RAD -- Come on man! There isn't even a pStr!!!
|
|
// if ( !cStringUtil::StringIsInteger( pStr ) )
|
|
if ( *psz != 0x00 )
|
|
{
|
|
TCERR << TSS_GetString( cTripwire, tripwire::STR_ERR_BAD_GMMS_VERBOSITY ) << std::endl;
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
mpData->mGmmsVerbosity = _ttoi(iter.ParamAt(0).c_str());
|
|
if (mpData->mGmmsVerbosity < 1 || mpData->mGmmsVerbosity > 2) {
|
|
TCERR << TSS_GetString( cTripwire, tripwire::STR_ERR_BAD_GMMS_VERBOSITY ) << std::endl;
|
|
return false;
|
|
}
|
|
bGmmsVerbositySpecified = true;
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
default:
|
|
// should I do anything, or just ignore this?
|
|
;
|
|
}
|
|
}
|
|
|
|
|
|
// if an editor is not provided in cfg or on cmdline, try to get it from environment
|
|
if( mpData->mbUpdate && mpData->mEditor.empty() )
|
|
util_GetEditor( mpData->mEditor );
|
|
|
|
//----------------------------------------
|
|
// I require the following information:
|
|
//
|
|
// * local key file
|
|
// * site key file
|
|
// * policy file
|
|
// * db file
|
|
// * report file
|
|
// * editor (if interactive is specified)
|
|
//-----------------------------------------
|
|
TEST_INIT_REQUIREMENT((! mpData->mLocalKeyFile.empty()), cTW, tw::STR_ERR_MISSING_LOCAL_KEY);
|
|
TEST_INIT_REQUIREMENT((! mpData->mSiteKeyFile.empty()), cTW, tw::STR_ERR_MISSING_SITE_KEY);
|
|
TEST_INIT_REQUIREMENT((! mpData->mPolFile.empty()), cTW, tw::STR_ERR_MISSING_POLICY);
|
|
TEST_INIT_REQUIREMENT((! mpData->mDbFile.empty()), cTW, tw::STR_ERR_MISSING_DB);
|
|
TEST_INIT_REQUIREMENT((! mpData->mReportFile.empty()), cTW, tw::STR_ERR_MISSING_REPORT);
|
|
TEST_INIT_REQUIREMENT((! (mpData->mEditor.empty() && mpData->mbUpdate)),cTW, tw::STR_ERR_MISSING_EDITOR);
|
|
|
|
#ifdef GMMS
|
|
if (bGmmsSpecified==false && bGmmsVerbositySpecified==true)
|
|
{
|
|
TCERR << TSS_GetString( cTripwire, tripwire::STR_ERR_GMMS_VERBOSITY_ONLY ) << std::endl;
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
///////////////////////////////////////////
|
|
// do some email-related verifications
|
|
///////////////////////////////////////////
|
|
if(mpData->mbEmail)
|
|
{
|
|
// make sure that email reporting and a file list were both not specified...
|
|
TEST_INIT_REQUIREMENT( mpData->mFilesToCheck.empty(), cTripwire, tripwire::STR_ERR_IC_EMAIL_AND_FILES );
|
|
|
|
// make sure that we have a valid mail method
|
|
TEST_INIT_REQUIREMENT( ( cMailMessage::NO_METHOD != mpData->mMailMethod ), cTripwire, tripwire::STR_ERR_NO_MAIL_METHOD );
|
|
TEST_INIT_REQUIREMENT( ( cMailMessage::INVALID_METHOD != mpData->mMailMethod ), cTripwire, tripwire::STR_ERR_INVALID_MAIL_METHOD );
|
|
|
|
// error if method is SENDMAIL and no MAILPROGRAM
|
|
TEST_INIT_REQUIREMENT( ( cMailMessage::MAIL_BY_PIPE != mpData->mMailMethod || !mpData->mMailProgram.empty()),
|
|
cTripwire, tripwire::STR_ERR_MISSING_MAILPROGRAM );
|
|
|
|
#if !SUPPORTS_MAPI
|
|
TEST_INIT_REQUIREMENT( ( cMailMessage::MAIL_BY_MAPI != mpData->mMailMethod ), cTripwire, tripwire::STR_ERR_MAPI_NOT_SUPPORTED );
|
|
#endif
|
|
}
|
|
|
|
// make sure that the config file and site key file are in sync...
|
|
//
|
|
if (cTWUtil::VerifyCfgSiteKey( mstrConfigFile, mpData->mSiteKeyFile ) == false)
|
|
cTWUtil::PrintErrorMsg(eTWCfgUnencrypted(_T(""), eError::NON_FATAL|eError::SUPRESS_THIRD_MSG));
|
|
|
|
#if IS_UNIX
|
|
// Set the cross file systems flag appropriately.
|
|
cFSDataSourceIter::SetFileSystemCrossing(mpData->mbCrossFileSystems);
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Execute
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
int cTWModeIC::Execute(cErrorQueue* pQueue)
|
|
{
|
|
cDebug d("cTWModeIC::Execute");
|
|
|
|
cFCODatabaseFile dbFile;
|
|
cFCODatabaseFile::iterator dbIter( dbFile );
|
|
cFCOReport report;
|
|
cFCOReportHeader reportHeader;
|
|
bool bEncrypted, bCheckMade = false, bEmailError = false;
|
|
try
|
|
{
|
|
|
|
// don't go any further if we won't be able to write the report to disk...
|
|
cFileUtil::TestFileWritable(mpData->mReportFile);
|
|
|
|
// open the database; note that ReadDatabase will set bEncrypted and open the
|
|
// key file if necessary
|
|
cKeyFile localKeyfile;
|
|
cTWUtil::OpenKeyFile(localKeyfile, mpData->mLocalKeyFile);
|
|
|
|
cTWUtil::ReadDatabase(mpData->mDbFile.c_str(), dbFile, localKeyfile.GetPublicKey(), bEncrypted);
|
|
|
|
//
|
|
// give a warning if the user that created the database is not the same as the user running right now...
|
|
//
|
|
TSTRING userName;
|
|
if( iFSServices::GetInstance()->GetCurrentUserName( userName ) )
|
|
{
|
|
if( dbFile.GetHeader().GetCreator().compare( userName.c_str() ) != 0 )
|
|
{
|
|
// TODO -- move these strings to the string table
|
|
TOSTRINGSTREAM str;
|
|
str << TSS_GetString( cTripwire, tripwire::STR_ERR2_DIFFERENT_USERS1) << dbFile.GetHeader().GetCreator()
|
|
<< TSS_GetString( cTripwire, tripwire::STR_ERR2_DIFFERENT_USERS2) << userName << std::ends;
|
|
cTWUtil::PrintErrorMsg( eICDifferentUsers( str.str(), eError::NON_FATAL ) );
|
|
}
|
|
}
|
|
|
|
// give a stern warning if the database is not encrypted
|
|
if(! bEncrypted && iUserNotify::GetInstance()->GetVerboseLevel() > iUserNotify::V_SILENT)
|
|
{
|
|
cTWUtil::PrintErrorMsg(eTWDbNotEncrypted(_T(""), eError::NON_FATAL|eError::SUPRESS_THIRD_MSG));
|
|
}
|
|
|
|
if( (!bEncrypted) && (mpData->mLocalProvided) && (!mpData->mbEncryptReport) )
|
|
{
|
|
//Issue a warning if a passphrase has been supplied, and the database is NOT encrypted.
|
|
cTWUtil::PrintErrorMsg( eTWPassForUnencryptedDb( _T(""), eError::NON_FATAL));
|
|
}
|
|
|
|
|
|
// get the password here if they are saving an encrypted report
|
|
const cElGamalSigPrivateKey* pPrivateKey = 0;
|
|
if(mpData->mbEncryptReport)
|
|
{
|
|
// if the key file isn't open (ie -- the report wasn't encrypted) then we need to
|
|
// open it now...
|
|
cTWUtil::OpenKeyFile(localKeyfile, mpData->mLocalKeyFile);
|
|
|
|
// open the private key for "early passphrase"
|
|
if(! mpData->mbLatePassphrase)
|
|
{
|
|
// OK, here is the deal: if the user specified a password on the command line
|
|
// and we are going to do an interactive update after the IC and both the report
|
|
// and db are encrypted, then we need to save the passphrase so it doesn't get
|
|
// scrambled by CreatePrivateKey
|
|
if(mpData->mLocalProvided && mpData->mbUpdate && bEncrypted)
|
|
{
|
|
wc16_string passPhrase = mpData->mLocalPassphrase.c_str();
|
|
pPrivateKey = cTWUtil::CreatePrivateKey(localKeyfile, passPhrase.c_str(), cTWUtil::KEY_LOCAL);
|
|
}
|
|
else
|
|
pPrivateKey = cTWUtil::CreatePrivateKey(localKeyfile, mpData->mLocalProvided ? mpData->mLocalPassphrase.c_str() : 0, cTWUtil::KEY_LOCAL);
|
|
}
|
|
}
|
|
|
|
// either integrity check using the policy file or a list of files
|
|
if(mpData->mFilesToCheck.size() != 0)
|
|
{
|
|
// we are checking files...
|
|
iUserNotify::GetInstance()->Notify(1, TSS_GetString( cTripwire, tripwire::STR_IC_FILES).c_str() );
|
|
////
|
|
// tell the user we are ignoring severity level and rule name, if they specified them...
|
|
//
|
|
if( ! mpData->mRuleName.empty() )
|
|
iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, TSS_GetString( cTripwire, tripwire::STR_IC_IGNORING_RULE_NAME).c_str() );
|
|
if( mpData->mbTrimBySeverity )
|
|
iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, TSS_GetString( cTripwire, tripwire::STR_IC_IGNORING_SEV_NUM).c_str() );
|
|
if( ! mpData->mSeverityName.empty() )
|
|
iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, TSS_GetString( cTripwire, tripwire::STR_IC_IGNORING_SEV_NAME).c_str() );
|
|
if( ! mpData->mGenreName.empty() )
|
|
iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, TSS_GetString( cTripwire, tripwire::STR_IC_IGNORING_GENRE_NAME).c_str() );
|
|
//
|
|
////
|
|
|
|
//**********************************
|
|
// new, experimental stuff.. trying out new command line interface
|
|
//
|
|
cTWUtil::GenreObjList listOut;
|
|
cTWUtil::ParseObjectList( listOut, mpData->mFilesToCheck );
|
|
//
|
|
// now, we will iterate over the list, performing an integrity check for each genre
|
|
//
|
|
for( cTWUtil::GenreObjList::iterator genreIter = listOut.begin(); genreIter != listOut.end(); genreIter++ )
|
|
{
|
|
dbIter.SeekToGenre( genreIter->first );
|
|
if( ! dbIter.Done() )
|
|
{
|
|
cGenreSwitcher::GetInstance()->SelectGenre( (cGenre::Genre)dbIter.GetGenre() );
|
|
std::auto_ptr<iParserGenreUtil> pParseUtil (iTWFactory::GetInstance()->CreateParserGenreUtil());
|
|
//
|
|
// I have to turn this into a list of cFCONames
|
|
//
|
|
std::list<cFCOName> fcoNames;
|
|
for(cTWUtil::ObjList::iterator it = genreIter->second.begin(); it != genreIter->second.end(); it++)
|
|
{
|
|
// if this is not an absolute path, warn and continue...
|
|
//
|
|
try
|
|
{
|
|
fcoNames.push_back( cTWUtil::ParseObjectName( *it ) );
|
|
}
|
|
catch( eError& e )
|
|
{
|
|
e.SetFatality( false );
|
|
pQueue->AddError( e );
|
|
report.GetErrorQueue()->AddError( e );
|
|
}
|
|
}
|
|
// TODO -- emit "processing XXX"
|
|
cIntegrityCheck ic( (cGenre::Genre)genreIter->first, dbIter.GetSpecList(), dbIter.GetDb(), report, pQueue );
|
|
|
|
uint32 icFlags = 0;
|
|
icFlags |= ( mpData->mfLooseDirs ? cIntegrityCheck::FLAG_LOOSE_DIR : 0 );
|
|
icFlags |= ( mpData->mbResetAccessTime ? cIntegrityCheck::FLAG_ERASE_FOOTPRINTS_IC : 0 );
|
|
|
|
ic.ExecuteOnObjectList( fcoNames, icFlags );
|
|
|
|
// put all info into report
|
|
cFCOReportGenreIter rgi( report );
|
|
rgi.SeekToGenre( (cGenre::Genre) genreIter->first );
|
|
rgi.GetGenreHeader().SetPropDisplayer( iTWFactory::GetInstance()->CreatePropDisplayer() );
|
|
rgi.GetGenreHeader().GetPropDisplayer()->Merge( dbIter.GetGenreHeader().GetPropDisplayer() );
|
|
rgi.GetGenreHeader().SetObjectsScanned( ic.ObjectsScanned() );
|
|
}
|
|
else
|
|
{
|
|
//TODO -- what is the right thing to do here?
|
|
// error and continue or exit?
|
|
//
|
|
eTWDbDoesntHaveGenre e( cGenreSwitcher::GetInstance()->GenreToString( (cGenre::Genre)genreIter->first, true ) );
|
|
e.SetFatality( false );
|
|
cTWUtil::PrintErrorMsg( e );
|
|
}
|
|
}
|
|
//
|
|
//**********************************
|
|
}
|
|
else
|
|
{
|
|
// we are checking a subset of the policy file
|
|
|
|
// parse the policy file
|
|
cGenreSpecListVector genreSpecList;
|
|
cTWCmdLineUtil::ParsePolicyFile(genreSpecList, mpData->mPolFile, mpData->mSiteKeyFile, pQueue);
|
|
|
|
//
|
|
// make sure the parsed policy is equivelant to the one in the database...
|
|
// TODO -- should this go in the report? should I make a report or just bail? I guess
|
|
// that for now, I will bail. (it throws an exception on failure
|
|
//
|
|
cTWCmdLineUtil::VerifyPolicy( genreSpecList, dbFile ) ;
|
|
|
|
//
|
|
// if they are only checking one genre, figure out which one it is ...
|
|
//
|
|
cGenre::Genre genreToCheck = cGenre::GENRE_INVALID;
|
|
if( ! mpData->mGenreName.empty() )
|
|
{
|
|
genreToCheck = cGenreSwitcher::GetInstance()->StringToGenre( mpData->mGenreName.c_str() );
|
|
if( genreToCheck == cGenre::GENRE_INVALID )
|
|
{
|
|
throw eICUnknownGenre( mpData->mGenreName );
|
|
}
|
|
if( ! cGenreSwitcher::GetInstance()->IsGenreAppropriate( genreToCheck ) )
|
|
{
|
|
throw eICInappropriateGenre( mpData->mGenreName );
|
|
}
|
|
|
|
iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL,
|
|
TSS_GetString( cTripwire, tripwire::STR_CHECKING_GENRE).c_str(),
|
|
cGenreSwitcher::GetInstance()->GenreToString( genreToCheck ) );
|
|
}
|
|
|
|
|
|
// iterate over the genres...
|
|
//
|
|
cGenreSpecListVector::iterator genreIter;
|
|
for (genreIter = genreSpecList.begin(); genreIter != genreSpecList.end(); ++genreIter)
|
|
{
|
|
// if they are only checking one genre and it is not this one, then
|
|
// skip everything else...
|
|
//
|
|
if( (genreToCheck != cGenre::GENRE_INVALID) && (genreToCheck != genreIter->GetGenre()) )
|
|
continue;
|
|
|
|
// make this genre the current genre.
|
|
//
|
|
cGenreSwitcher::GetInstance()->SelectGenre( genreIter->GetGenre() );
|
|
//
|
|
// seek the database iter to this genre...
|
|
//
|
|
dbIter.SeekToGenre( genreIter->GetGenre() );
|
|
if( dbIter.Done() )
|
|
{
|
|
// TODO -- what is the right thing to do here? throw or warn and continue?
|
|
// I think that I should add it to the report's error queue and spit it to
|
|
// stderr and continue
|
|
//
|
|
TCERR << _T("Genre ") << cGenreSwitcher::GetInstance()->GenreToString( genreIter->GetGenre() )
|
|
<< _T(" not in database; skipping.") << std::endl;
|
|
continue;
|
|
}
|
|
// message to the user...
|
|
//
|
|
iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL,
|
|
TSS_GetString( cTripwire, tripwire::STR_PROCESSING_GENRE ).c_str(),
|
|
cGenreSwitcher::GetInstance()->GenreToString( cGenreSwitcher::GetInstance()->CurrentGenre(), true ) );
|
|
|
|
cFCOSpecList specList = genreIter->GetSpecList();
|
|
|
|
// trim ignored properties from the specs...
|
|
if(! mpData->mIgnoreProps.empty())
|
|
cTWCmdLineUtil::TrimPropsFromSpecs(specList, mpData->mIgnoreProps);
|
|
|
|
// trim ignored rule names from the specs...
|
|
if(! mpData->mRuleName.empty())
|
|
cTWCmdLineUtil::TrimSpecsByName(specList, mpData->mRuleName);
|
|
|
|
// trim spec list based on severity
|
|
if(mpData->mbTrimBySeverity)
|
|
cTWCmdLineUtil::TrimSpecsBySeverity(specList, mpData->mSeverityLevel);
|
|
|
|
// trim specs by severity name
|
|
if(! mpData->mSeverityName.empty())
|
|
cTWCmdLineUtil::TrimSpecsBySeverityName(specList, mpData->mSeverityName);
|
|
|
|
//
|
|
// only do the integrity check if there is something to check!
|
|
//
|
|
if( ! specList.IsEmpty() )
|
|
{
|
|
bCheckMade = true; //we've checked at least one rule.
|
|
|
|
// do the integrity check...
|
|
iUserNotify::GetInstance()->Notify(1, TSS_GetString( cTripwire, tripwire::STR_INTEGRITY_CHECK).c_str());
|
|
|
|
#ifdef TW_PROFILE
|
|
cWin32TaskTimer timer("cTripwire::IntegrityCheck");
|
|
timer.Start();
|
|
#endif
|
|
cIntegrityCheck ic( (cGenre::Genre)dbIter.GetGenre(), specList, dbIter.GetDb(), report, pQueue );
|
|
|
|
uint32 icFlags = 0;
|
|
icFlags |= ( mpData->mfLooseDirs ? cIntegrityCheck::FLAG_LOOSE_DIR : 0 );
|
|
icFlags |= ( mpData->mbResetAccessTime ? cIntegrityCheck::FLAG_ERASE_FOOTPRINTS_IC : 0 );
|
|
|
|
ic.Execute( icFlags );
|
|
|
|
// put all display info into report
|
|
cFCOReportGenreIter rgi( report );
|
|
rgi.SeekToGenre( (cGenre::Genre) dbIter.GetGenre() );
|
|
rgi.GetGenreHeader().SetPropDisplayer( iTWFactory::GetInstance()->CreatePropDisplayer() );
|
|
rgi.GetGenreHeader().GetPropDisplayer()->Merge( dbIter.GetGenreHeader().GetPropDisplayer() );
|
|
rgi.GetGenreHeader().SetObjectsScanned( ic.ObjectsScanned() );
|
|
|
|
#ifdef TW_PROFILE
|
|
timer.Stop();
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL,
|
|
TSS_GetString( cTripwire, tripwire::STR_ERR_IC_NO_SPECS_LEFT).c_str(),
|
|
cGenreSwitcher::GetInstance()->GenreToString( genreIter->GetGenre(), true ) );
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
// save out the report...
|
|
cFCOReportUtil::CalculateHeaderInfo(
|
|
reportHeader,
|
|
mpData->mPolFile,
|
|
mstrConfigFile,
|
|
mpData->mDbFile,
|
|
mstrCmdLine,
|
|
cSystemInfo::GetExeStartTime(),
|
|
dbFile.GetHeader().GetLastDBUpdateTime()
|
|
);
|
|
|
|
cFCOReportUtil::FinalizeReport( report );
|
|
|
|
#ifdef GMMS
|
|
// gmms reporting?
|
|
if (mpData->mbGmms)
|
|
{
|
|
try
|
|
{
|
|
cTWCmdLineUtil::GmmsReport(reportHeader, report, mpData->mGmmsProg, mpData->mGmmsOptions, mpData->mGmmsVerbosity);
|
|
}
|
|
catch(eGmmsError& e)
|
|
{
|
|
cTWUtil::PrintErrorMsg(e);
|
|
// Do not return. Gmms errors are not fatal.
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// email the report if that is desired...
|
|
if(mpData->mbEmail)
|
|
{
|
|
bEmailError = cTWCmdLineUtil::EmailReport(reportHeader, report, mpData) == 0;
|
|
|
|
// We should notify them that no email was sent should the following condition
|
|
// apply.
|
|
if( !bCheckMade )
|
|
{
|
|
iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL,
|
|
TSS_GetString( cTripwire, tripwire::STR_IC_NOEMAIL_SENT).c_str(),
|
|
_T("") );
|
|
}
|
|
}
|
|
|
|
// write the report to disk...
|
|
if(mpData->mbEncryptReport)
|
|
{
|
|
// get the private key for "late passphrase"
|
|
if(! pPrivateKey)
|
|
{
|
|
ASSERT(mpData->mbLatePassphrase);
|
|
// OK, here is the deal: if the user specified a password on the command line
|
|
// and we are going to do an interactive update after the IC and both the report
|
|
// and db are encrypted, then we need to save the passphrase so it doesn't get
|
|
// scrambled by CreatePrivateKey
|
|
if(mpData->mLocalProvided && mpData->mbUpdate && bEncrypted)
|
|
{
|
|
wc16_string passPhrase = mpData->mLocalPassphrase.c_str();
|
|
pPrivateKey = cTWUtil::CreatePrivateKey(localKeyfile, passPhrase.c_str(), cTWUtil::KEY_LOCAL);
|
|
}
|
|
else
|
|
pPrivateKey = cTWUtil::CreatePrivateKey(localKeyfile, mpData->mLocalProvided ? mpData->mLocalPassphrase.c_str() : 0, cTWUtil::KEY_LOCAL);
|
|
}
|
|
|
|
// backup the file we are about to overwrite
|
|
cFileUtil::BackupFile(mpData->mReportFile);
|
|
|
|
// write the report
|
|
cTWUtil::WriteReport(mpData->mReportFile.c_str(), reportHeader, report, true, pPrivateKey);
|
|
localKeyfile.ReleasePrivateKey();
|
|
}
|
|
else
|
|
{
|
|
cFileUtil::BackupFile(mpData->mReportFile); // backup the file we are about to overwrite
|
|
cTWUtil::WriteReport(mpData->mReportFile.c_str(), reportHeader, report, false, NULL); // false means no encryption
|
|
}
|
|
|
|
// print a text version of the report to stdout...
|
|
if(mpData->mbPrintToStdout)
|
|
{
|
|
// print a couple of new lines so that the report isn't butted up against the rest of the output.
|
|
iUserNotify::GetInstance()->Notify(iUserNotify::V_NORMAL, _T("\n\n"));
|
|
cTextReportViewer trv( reportHeader, report );
|
|
trv.PrintTextReport( _T("-"), cTextReportViewer::SUMMARY_ONLY );
|
|
}
|
|
|
|
}
|
|
catch(eError& e)
|
|
{
|
|
if (mpData->mbLogToSyslog)
|
|
{
|
|
TSTRING msg = TSS_GetString( cTripwire, tripwire::STR_SYSLOG_IC_FAIL_MSG );
|
|
msg.append(cErrorTable::GetInstance()->Get( e.GetID() ));
|
|
|
|
cSyslog::Log(TSS_GetString( cTripwire, tripwire::STR_SYSLOG_IDENT ).c_str(), cSyslog::LOG_ERROR, msg.c_str());
|
|
}
|
|
|
|
cTWUtil::PrintErrorMsg(e);
|
|
return 8;
|
|
//TODO -- send a sad email here if mbEmail == true
|
|
}
|
|
|
|
// tell the user the report was saved
|
|
iUserNotify::GetInstance()->Notify(1, TSS_GetString( cTripwire, tripwire::STR_IC_SUCCESS).c_str());
|
|
|
|
if (mpData->mbLogToSyslog)
|
|
{
|
|
cTextReportViewer trv( reportHeader, report );
|
|
TSTRING msg = TSS_GetString( cTripwire, tripwire::STR_SYSLOG_IC_MSG );
|
|
msg.append(mpData->mDbFile);
|
|
msg.append(_T(" "));
|
|
msg.append(trv.SingleLineReport());
|
|
cSyslog::Log(TSS_GetString( cTripwire, tripwire::STR_SYSLOG_IDENT ).c_str(), cSyslog::LOG_SUCCESS, msg.c_str());
|
|
}
|
|
|
|
// go directly into interactive update if that is what they want...
|
|
//
|
|
if(mpData->mbUpdate)
|
|
{
|
|
cTWModeDbUpdate dbUpdate;
|
|
dbUpdate.Init(mpData, &dbFile, &reportHeader, &report, bEncrypted);
|
|
int ret = dbUpdate.Execute(pQueue);
|
|
|
|
if (ret != 0)
|
|
return ret;
|
|
}
|
|
|
|
// the return level is based on the type of violations that were found:
|
|
// 1 = added files
|
|
// 2 = removed files
|
|
// 4 = changed files
|
|
// 8 = ERROR_IC = Execution Error
|
|
if(bEmailError)
|
|
return (ERROR_IC | cTWCmdLineUtil::GetICReturnValue(report));
|
|
else
|
|
return cTWCmdLineUtil::GetICReturnValue(report);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// GetModeUsage
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
TSTRING cTWModeIC::GetModeUsage( void )
|
|
{
|
|
return ( TSS_GetString( cTripwire, tripwire::STR_TRIPWIRE_HELP_CHECK ) );
|
|
}
|
|
|
|
//#############################################################################
|
|
// cTWModeDbUpdate
|
|
//#############################################################################
|
|
class cTWModeDbUpdate_i : public cTWModeCommon
|
|
{
|
|
public:
|
|
bool mbInteractive; // don't do interactive update; just integrate the report file
|
|
bool mbAnal; // are we in anal mode?
|
|
//std::string mSitePassphrase; // pass phrase for site key
|
|
//bool mSiteProvided;
|
|
|
|
// these members are only used when this mode is entered after integrity checking.
|
|
// they are set to variables that are on cTWModeIC's stack, so they should _not_ be deleted.
|
|
// if they are non-null when Execute() is called, they should be used as the db and report.
|
|
bool mbEncryptDb;
|
|
cFCOReport* mpReport;
|
|
cFCODatabaseFile* mpDbFile;
|
|
cFCOReportHeader* mpReportHeader;
|
|
|
|
// ctor can set up some default values
|
|
cTWModeDbUpdate_i() : cTWModeCommon(), mbInteractive(true), mbAnal(true), /*mSiteProvided(false),*/ mpReport(0), mpDbFile(0), mpReportHeader(0) {}
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// ctor, dtor
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
cTWModeDbUpdate::cTWModeDbUpdate()
|
|
{
|
|
mpData = new cTWModeDbUpdate_i;
|
|
}
|
|
|
|
|
|
|
|
cTWModeDbUpdate::~cTWModeDbUpdate()
|
|
{
|
|
delete mpData;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// InitCmdLineParser
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void cTWModeDbUpdate::InitCmdLineParser(cCmdLineParser& cmdLine)
|
|
{
|
|
// initialize the switches common to all modes...
|
|
InitCmdLineCommon(cmdLine);
|
|
|
|
cmdLine.AddArg(cTWCmdLine::MODE_UPDATE_DB, TSTRING(_T("")), TSTRING(_T("update")), cCmdLineParser::PARAM_NONE);
|
|
cmdLine.AddArg(cTWCmdLine::ACCEPT_ALL, TSTRING(_T("a")), TSTRING(_T("accept-all")), cCmdLineParser::PARAM_NONE);
|
|
cmdLine.AddArg(cTWCmdLine::ANAL_LEVEL, TSTRING(_T("Z")), TSTRING(_T("secure-mode")), cCmdLineParser::PARAM_ONE);
|
|
cmdLine.AddArg(cTWCmdLine::EDITOR, TSTRING(_T("V")), TSTRING(_T("visual")), cCmdLineParser::PARAM_ONE);
|
|
cmdLine.AddArg(cTWCmdLine::PARAMS, TSTRING(_T("")), TSTRING(_T("")), cCmdLineParser::PARAM_NONE);
|
|
|
|
// mutual exclusion...
|
|
cmdLine.AddMutEx(cTWCmdLine::ACCEPT_ALL, cTWCmdLine::EDITOR);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Init
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool cTWModeDbUpdate::Init(const cConfigFile& cf, const cCmdLineParser& cmdLine)
|
|
{
|
|
// first, fill out everything with the config file info...
|
|
FillOutConfigInfo(mpData, cf);
|
|
|
|
// now, parse the command line...
|
|
// this takes care of the common stuff...
|
|
FillOutCmdLineInfo(mpData, cmdLine);
|
|
|
|
// now do the stuff specific to this mode...
|
|
cCmdLineIter iter(cmdLine);
|
|
for(iter.SeekBegin(); ! iter.Done(); iter.Next())
|
|
{
|
|
switch(iter.ArgId())
|
|
{
|
|
case cTWCmdLine::ACCEPT_ALL:
|
|
mpData->mbInteractive = false;
|
|
break;
|
|
case cTWCmdLine::ANAL_LEVEL:
|
|
ASSERT(iter.NumParams() > 0);
|
|
if(iter.ParamAt(0).compare(_T("high")) == 0)
|
|
mpData->mbAnal = true;
|
|
else if(iter.ParamAt(0).compare(_T("low")) == 0)
|
|
mpData->mbAnal = false;
|
|
else
|
|
{
|
|
// invalid parameter to anal switch...
|
|
// TODO -- print this to stderr; how do I display (1) the switch name
|
|
// and (2) the possible values?
|
|
// TODO -- move {high, low} somewhere else
|
|
TCERR << TSS_GetString( cTripwire, tripwire::STR_ERR_BAD_PARAM) << _T(" : ")
|
|
<< iter.ParamAt(0).c_str() << _T("; must be {high, low}") << std::endl;
|
|
return false;
|
|
}
|
|
break;
|
|
case cTWCmdLine::EDITOR:
|
|
ASSERT(iter.NumParams() > 0);
|
|
mpData->mEditor = iter.ParamAt(0);
|
|
break;
|
|
default:
|
|
// should I do anything, or just ignore this?
|
|
;
|
|
}
|
|
}
|
|
|
|
// if an editor is not provided in cfg or on cmdline, try to get it from environment
|
|
if( mpData->mbInteractive && mpData->mEditor.empty() )
|
|
util_GetEditor( mpData->mEditor );
|
|
|
|
//----------------------------------------
|
|
// I require the following information:
|
|
//
|
|
// * local key file
|
|
// * site key file
|
|
// * policy file
|
|
// * db file
|
|
// * report file
|
|
// * editor (if accept all is not specified)
|
|
//-----------------------------------------
|
|
TEST_INIT_REQUIREMENT((! mpData->mLocalKeyFile.empty()), cTW, tw::STR_ERR_MISSING_LOCAL_KEY);
|
|
TEST_INIT_REQUIREMENT((! mpData->mSiteKeyFile.empty()), cTW, tw::STR_ERR_MISSING_SITE_KEY);
|
|
TEST_INIT_REQUIREMENT((! mpData->mPolFile.empty()), cTW, tw::STR_ERR_MISSING_POLICY);
|
|
TEST_INIT_REQUIREMENT((! mpData->mDbFile.empty()), cTW, tw::STR_ERR_MISSING_DB);
|
|
TEST_INIT_REQUIREMENT((! mpData->mReportFile.empty()), cTW, tw::STR_ERR_MISSING_REPORT);
|
|
TEST_INIT_REQUIREMENT(((!mpData->mEditor.empty()) || (!mpData->mbInteractive)), cTW, tw::STR_ERR_MISSING_EDITOR);
|
|
|
|
// make sure that the config file and site key file are in sync...
|
|
//
|
|
if (cTWUtil::VerifyCfgSiteKey( mstrConfigFile, mpData->mSiteKeyFile ) == false)
|
|
cTWUtil::PrintErrorMsg(eTWCfgUnencrypted(_T(""), eError::NON_FATAL|eError::SUPRESS_THIRD_MSG));
|
|
|
|
#if IS_UNIX
|
|
// Set the cross file systems flag appropriately.
|
|
cFSDataSourceIter::SetFileSystemCrossing(mpData->mbCrossFileSystems);
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
void cTWModeDbUpdate::Init(const cTWModeIC_i* pICData, cFCODatabaseFile* dbFile, cFCOReportHeader* prh, cFCOReport* pReport, bool bEncryptDb)
|
|
{
|
|
mpData->mbInteractive = true; // always interactive
|
|
mpData->mbAnal = pICData->mbAnal;
|
|
//mpData->mbBackup = pICData->mbBackup;
|
|
mpData->mDbFile = pICData->mDbFile;
|
|
mpData->mLocalKeyFile = pICData->mLocalKeyFile;
|
|
mpData->mLocalPassphrase= pICData->mLocalPassphrase;
|
|
mpData->mLocalProvided = pICData->mLocalProvided;
|
|
mpData->mPolFile = pICData->mPolFile;
|
|
mpData->mReportFile = pICData->mReportFile;
|
|
mpData->mSiteKeyFile = pICData->mSiteKeyFile;
|
|
mpData->mVerbosity = pICData->mVerbosity;
|
|
mpData->mEditor = pICData->mEditor;
|
|
mpData->mbLatePassphrase= pICData->mbLatePassphrase;
|
|
|
|
|
|
mpData->mbEncryptDb = bEncryptDb;
|
|
mpData->mpDbFile = dbFile;
|
|
|
|
if(pReport)
|
|
{
|
|
ASSERT(prh != 0);
|
|
mpData->mpReport = pReport;
|
|
mpData->mpReportHeader = prh;
|
|
}
|
|
else
|
|
{
|
|
mpData->mpReport = 0;
|
|
mpData->mpReportHeader = 0;
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Execute
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
int cTWModeDbUpdate::Execute(cErrorQueue* pQueue)
|
|
{
|
|
try
|
|
{
|
|
// don't go any further if we won't be able to write to the db file...
|
|
cFileUtil::TestFileWritable(mpData->mDbFile);
|
|
|
|
// open the database
|
|
cFCODatabaseFile dbFile;
|
|
cKeyFile localKeyfile;
|
|
bool bDbEncrypted, bReportEncrypted;
|
|
|
|
cTWUtil::OpenKeyFile(localKeyfile, mpData->mLocalKeyFile);
|
|
|
|
if(! mpData->mpDbFile)
|
|
{
|
|
// open the database; note that ReadDatabase will set bEncrypted and open the
|
|
// key file if necessary
|
|
cTWUtil::ReadDatabase(mpData->mDbFile.c_str(), dbFile, localKeyfile.GetPublicKey(), bDbEncrypted);
|
|
mpData->mpDbFile = &dbFile;
|
|
}
|
|
else
|
|
{
|
|
// we were passed the database; we should open the key file now if the db needs
|
|
// to be saved encrypted...
|
|
if(mpData->mbEncryptDb)
|
|
bDbEncrypted = true;
|
|
else
|
|
bDbEncrypted = false;
|
|
}
|
|
|
|
if( (!bDbEncrypted) && (mpData->mLocalProvided) )
|
|
{
|
|
//Issue a warning if a passphrase has been supplied, and the database is NOT encrypted.
|
|
cTWUtil::PrintErrorMsg( eTWPassForUnencryptedDb( _T(""), eError::NON_FATAL));
|
|
}
|
|
|
|
|
|
// open the report...
|
|
cFCOReport report;
|
|
cFCOReportHeader reportHeader;
|
|
if(! mpData->mpReport)
|
|
{
|
|
cTWUtil::ReadReport(mpData->mReportFile.c_str(), reportHeader, report, localKeyfile.GetPublicKey(), false, bReportEncrypted);
|
|
mpData->mpReport = &report;
|
|
mpData->mpReportHeader = &reportHeader;
|
|
}
|
|
else
|
|
ASSERT(mpData->mpReportHeader != 0);
|
|
|
|
// open the private key for "early passphrase"
|
|
// I don't think that early passphrase should apply to db update; there is no reason the user
|
|
// would want to enter the passphrase before editing the report .. mdb
|
|
// TODO: Well ok, can we remove this commented out code then?
|
|
const cElGamalSigPrivateKey* pPrivateKey = 0;
|
|
/*
|
|
if(bDbEncrypted && (! mpData->mbLatePassphrase))
|
|
{
|
|
pPrivateKey = cTWUtil::CreatePrivateKey(localKeyfile, mLocalProvided ? mpData->mLocalPassphrase.c_str() : 0);
|
|
}
|
|
*/
|
|
|
|
// have the user modify the report, if they want to
|
|
if(mpData->mbInteractive)
|
|
{
|
|
// put a try/catch here to allow ourselves to print a message
|
|
// saying the editor launch failed
|
|
try
|
|
{
|
|
cTextReportViewer trv( *mpData->mpReportHeader, *mpData->mpReport );
|
|
trv.DisplayReportAndHaveUserUpdateIt( mpData->mEditor, cTextReportViewer::FULL_REPORT );
|
|
}
|
|
catch(...)
|
|
{
|
|
TCERR << TSS_GetString( cTripwire, tripwire::STR_ERR_UPDATE_ED_LAUNCH) << std::endl;
|
|
throw;
|
|
}
|
|
}
|
|
|
|
// if the report is empty, there is no need to do the update...
|
|
if(! cTWCmdLineUtil::ReportContainsFCO(*mpData->mpReport))
|
|
{
|
|
// tell them ...
|
|
iUserNotify::GetInstance()->Notify(1, TSS_GetString( cTripwire, tripwire::STR_REPORT_EMPTY).c_str());
|
|
// keep those pesky ASSERTs from cKeyFile away!
|
|
if(pPrivateKey)
|
|
localKeyfile.ReleasePrivateKey();
|
|
return 0; // is this the right return val?
|
|
}
|
|
|
|
// give a stern warning if the database is not encrypted
|
|
if(! bDbEncrypted && iUserNotify::GetInstance()->GetVerboseLevel() > iUserNotify::V_SILENT)
|
|
{
|
|
// warn if the database is not encrytped
|
|
cTWUtil::PrintErrorMsg(eTWDbNotEncrypted(_T(""), eError::NON_FATAL|eError::SUPRESS_THIRD_MSG));
|
|
}
|
|
|
|
// iterate over all the genres in the report...
|
|
//
|
|
cFCOReportGenreIter genreIter( *mpData->mpReport );
|
|
for( genreIter.SeekBegin(); ! genreIter.Done(); genreIter.Next() )
|
|
{
|
|
cGenreSwitcher::GetInstance()->SelectGenre( genreIter.GetGenre() );
|
|
//
|
|
// seek the db iter to the current genre...
|
|
//
|
|
cFCODatabaseFile::iterator dbIter( *mpData->mpDbFile );
|
|
dbIter.SeekToGenre( genreIter.GetGenre() );
|
|
if( dbIter.Done() )
|
|
{
|
|
//TODO -- what is the right thing to do here?
|
|
//
|
|
ASSERT( false );
|
|
throw eTWDbDoesntHaveGenre();
|
|
}
|
|
//
|
|
// actually do the integrity check...
|
|
//
|
|
uint32 udFlags = 0;
|
|
udFlags |= ( mpData->mbResetAccessTime ? cUpdateDb::FLAG_ERASE_FOOTPRINTS_UD : 0 );
|
|
|
|
cUpdateDb update( dbIter.GetDb(), *mpData->mpReport, pQueue );
|
|
if( (! update.Execute( udFlags )) && mpData->mbAnal )
|
|
{
|
|
// we will not perform the update; simply exit.
|
|
TCOUT << TSS_GetString( cTripwire, tripwire::STR_DB_NOT_UPDATED) << std::endl;
|
|
return 8;
|
|
}
|
|
|
|
//
|
|
// update the header info for the database...
|
|
//
|
|
// merge the prop displayers...
|
|
dbIter.GetGenreHeader().GetPropDisplayer()->Merge( genreIter.GetGenreHeader().GetPropDisplayer() );
|
|
}
|
|
|
|
// Update the header
|
|
// Note: We DO NOT call cFCODatabaseUtil::CalculateHeader() here. We only
|
|
// want to update these entries.
|
|
mpData->mpDbFile->GetHeader().SetCreator(cTWUtil::GetCurrentUser());
|
|
mpData->mpDbFile->GetHeader().SetLastDBUpdateTime( cSystemInfo::GetExeStartTime() );
|
|
|
|
//
|
|
// write the db to disk...
|
|
//
|
|
if(bDbEncrypted)
|
|
{
|
|
// open the private key for "late prompting"
|
|
if(! pPrivateKey)
|
|
{
|
|
pPrivateKey = cTWUtil::CreatePrivateKey(localKeyfile, mpData->mLocalProvided ? mpData->mLocalPassphrase.c_str() : 0, cTWUtil::KEY_LOCAL);
|
|
}
|
|
|
|
// backup the file we are about to overwrite
|
|
cFileUtil::BackupFile(mpData->mDbFile);
|
|
|
|
cTWUtil::WriteDatabase(mpData->mDbFile.c_str(), *mpData->mpDbFile, true, pPrivateKey);
|
|
localKeyfile.ReleasePrivateKey();
|
|
}
|
|
else
|
|
{
|
|
cFileUtil::BackupFile(mpData->mDbFile); // backup the file we are about to overwrite
|
|
cTWUtil::WriteDatabase(mpData->mDbFile.c_str(), *mpData->mpDbFile, false, NULL); // false means no encryption
|
|
}
|
|
}
|
|
catch(eError& e)
|
|
{
|
|
if (mpData->mbLogToSyslog)
|
|
{
|
|
TSTRING msg = TSS_GetString( cTripwire, tripwire::STR_SYSLOG_UP_FAIL_MSG );
|
|
msg.append(cErrorTable::GetInstance()->Get( e.GetID() ));
|
|
|
|
cSyslog::Log(TSS_GetString( cTripwire, tripwire::STR_SYSLOG_IDENT ).c_str(), cSyslog::LOG_ERROR, msg.c_str());
|
|
}
|
|
|
|
cTWUtil::PrintErrorMsg(e);
|
|
return 8;
|
|
}
|
|
|
|
if (mpData->mbLogToSyslog)
|
|
{
|
|
TSTRING msg = TSS_GetString( cTripwire, tripwire::STR_SYSLOG_UP_MSG );
|
|
msg.append(mpData->mDbFile);
|
|
cSyslog::Log(TSS_GetString( cTripwire, tripwire::STR_SYSLOG_IDENT ).c_str(), cSyslog::LOG_SUCCESS, msg.c_str());
|
|
}
|
|
|
|
// everything went ok; return 0
|
|
return 0;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// GetModeUsage
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
TSTRING cTWModeDbUpdate::GetModeUsage( void )
|
|
{
|
|
return ( TSS_GetString( cTripwire, tripwire::STR_TRIPWIRE_HELP_UPDATE ) );
|
|
}
|
|
|
|
//#############################################################################
|
|
// cTWModePolUpdate
|
|
//#############################################################################
|
|
class cTWModePolUpdate_i : public cTWModeCommon
|
|
{
|
|
public:
|
|
TSTRING mTextPolFile;
|
|
wc16_string mSitePassphrase;
|
|
bool mSiteProvided;
|
|
bool mbAnal;
|
|
|
|
// ctor can set up some default values
|
|
cTWModePolUpdate_i() : cTWModeCommon(), mSiteProvided(false), mbAnal(true) {}
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// ctor, dtor
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
cTWModePolUpdate::cTWModePolUpdate()
|
|
{
|
|
mpData = new cTWModePolUpdate_i;
|
|
}
|
|
|
|
cTWModePolUpdate::~cTWModePolUpdate()
|
|
{
|
|
delete mpData;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// InitCmdLineParser
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void cTWModePolUpdate::InitCmdLineParser(cCmdLineParser& cmdLine)
|
|
{
|
|
// initialize the switches common to all modes...
|
|
InitCmdLineCommon(cmdLine);
|
|
|
|
cmdLine.AddArg(cTWCmdLine::MODE_UPDATE_POL, TSTRING(_T("")), TSTRING(_T("update-policy")), cCmdLineParser::PARAM_NONE);
|
|
cmdLine.AddArg(cTWCmdLine::TEXT_POL_FILE, TSTRING(_T("")), TSTRING(_T("")), cCmdLineParser::PARAM_ONE);
|
|
cmdLine.AddArg(cTWCmdLine::LOCAL_PASSPHRASE,TSTRING(_T("P")), TSTRING(_T("local-passphrase")), cCmdLineParser::PARAM_ONE);
|
|
cmdLine.AddArg(cTWCmdLine::SITE_PASSPHRASE, TSTRING(_T("Q")), TSTRING(_T("site-passphrase")), cCmdLineParser::PARAM_ONE);
|
|
cmdLine.AddArg(cTWCmdLine::ANAL_LEVEL, TSTRING(_T("Z")), TSTRING(_T("secure-mode")), cCmdLineParser::PARAM_ONE);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Init
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool cTWModePolUpdate::Init(const cConfigFile& cf, const cCmdLineParser& cmdLine)
|
|
{
|
|
// first, fill out everything with the config file info...
|
|
FillOutConfigInfo(mpData, cf);
|
|
|
|
// now, parse the command line...
|
|
// this takes care of the common stuff...
|
|
FillOutCmdLineInfo(mpData, cmdLine);
|
|
|
|
// now do the stuff specific to this mode...
|
|
cCmdLineIter iter(cmdLine);
|
|
for(iter.SeekBegin(); ! iter.Done(); iter.Next())
|
|
{
|
|
TSTRING fullPath;
|
|
switch(iter.ArgId())
|
|
{
|
|
case cTWCmdLine::TEXT_POL_FILE:
|
|
ASSERT(iter.NumParams() > 0);
|
|
mpData->mTextPolFile = iter.ParamAt(0);
|
|
//
|
|
// convert it to a full path
|
|
//
|
|
if( iFSServices::GetInstance()->FullPath( fullPath, mpData->mTextPolFile ) )
|
|
mpData->mTextPolFile = fullPath;
|
|
break;
|
|
case cTWCmdLine::SITE_PASSPHRASE:
|
|
ASSERT(iter.NumParams() > 0);
|
|
mpData->mSitePassphrase = cStringUtil::TstrToWstr(iter.ParamAt(0));
|
|
mpData->mSiteProvided = true;
|
|
break;
|
|
case cTWCmdLine::ANAL_LEVEL:
|
|
ASSERT(iter.NumParams() > 0);
|
|
if(iter.ParamAt(0).compare(_T("high")) == 0)
|
|
mpData->mbAnal = true;
|
|
else if(iter.ParamAt(0).compare(_T("low")) == 0)
|
|
mpData->mbAnal = false;
|
|
else
|
|
{
|
|
// invalid parameter to anal switch...
|
|
// TODO -- print this to stderr; how do I display (1) the switch name
|
|
// and (2) the possible values?
|
|
// TODO -- move {high, low} somewhere else
|
|
TCERR << TSS_GetString( cTripwire, tripwire::STR_ERR_BAD_PARAM) << _T(" : ")
|
|
<< iter.ParamAt(0).c_str() << _T("; must be {high, low}") << std::endl;
|
|
return false;
|
|
}
|
|
break;
|
|
default:
|
|
// should I do anything, or just ignore this?
|
|
;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------
|
|
// I require the following information:
|
|
//
|
|
// * local key file
|
|
// * site key file
|
|
// * policy file
|
|
// * db file
|
|
//-----------------------------------------
|
|
TEST_INIT_REQUIREMENT((! mpData->mLocalKeyFile.empty()), cTW, tw::STR_ERR_MISSING_LOCAL_KEY);
|
|
TEST_INIT_REQUIREMENT((! mpData->mSiteKeyFile.empty()), cTW, tw::STR_ERR_MISSING_SITE_KEY);
|
|
TEST_INIT_REQUIREMENT((! mpData->mPolFile.empty()), cTW, tw::STR_ERR_MISSING_POLICY);
|
|
TEST_INIT_REQUIREMENT((! mpData->mDbFile.empty()), cTW, tw::STR_ERR_MISSING_DB);
|
|
|
|
// if a passphrase was passed on the command line, then late prompting should
|
|
// be set to false so that wrong passwords are detected immediately
|
|
//
|
|
// Note that the local passphrase was already checked against in FillOutCmdLineInfo(),
|
|
// so I only need to test the site passphrase
|
|
if( mpData->mSiteProvided && mpData->mbLatePassphrase )
|
|
{
|
|
// TODO -- I don't know if we should display this or not -- mdb
|
|
//iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, TSS_GetString( cTripwire, tripwire::STR_NOTIFY_CHANGE_PROMPT_TIME).c_str() );
|
|
mpData->mbLatePassphrase = false;
|
|
}
|
|
|
|
// make sure that the config file and site key file are in sync...
|
|
//
|
|
if (cTWUtil::VerifyCfgSiteKey( mstrConfigFile, mpData->mSiteKeyFile ) == false)
|
|
cTWUtil::PrintErrorMsg(eTWCfgUnencrypted(_T(""), eError::NON_FATAL|eError::SUPRESS_THIRD_MSG));
|
|
|
|
|
|
#if IS_UNIX
|
|
// Set the cross file systems flag appropriately.
|
|
cFSDataSourceIter::SetFileSystemCrossing(mpData->mbCrossFileSystems);
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Execute
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
int cTWModePolUpdate::Execute(cErrorQueue* pQueue)
|
|
{
|
|
try
|
|
{
|
|
// make sure all of the files are accessable
|
|
cFileUtil::TestFileWritable(mpData->mPolFile);
|
|
cFileUtil::TestFileWritable(mpData->mDbFile);
|
|
|
|
// open and parse the new policy file...
|
|
cGenreSpecListVector genreSpecList;
|
|
cTWCmdLineUtil::ParseTextPolicyFile(genreSpecList, mpData->mTextPolFile, mpData->mSiteKeyFile, pQueue);
|
|
|
|
cFCODatabaseFile dbFile;
|
|
cKeyFile localKeyfile, siteKeyfile;
|
|
cPrivateKeyProxy privateLocal, privateSite;
|
|
cTWUtil::OpenKeyFile(localKeyfile, mpData->mLocalKeyFile);
|
|
cTWUtil::OpenKeyFile(siteKeyfile, mpData->mSiteKeyFile);
|
|
|
|
// open the old database; note that ReadDatabase will set bEncrypted and open the
|
|
// key file if necessary
|
|
bool bDbEncrypted;
|
|
bool bPolEncrypted = true;
|
|
|
|
cTWUtil::ReadDatabase(mpData->mDbFile.c_str(), dbFile, localKeyfile.GetPublicKey(), bDbEncrypted);
|
|
|
|
//
|
|
// give a warning if the user that created the database is not the same as the user running right now...
|
|
//
|
|
TSTRING userName;
|
|
if( iFSServices::GetInstance()->GetCurrentUserName( userName ) )
|
|
{
|
|
if( dbFile.GetHeader().GetCreator().compare( userName.c_str() ) != 0 )
|
|
{
|
|
// TODO -- move these strings to the string table
|
|
TOSTRINGSTREAM str;
|
|
str << TSS_GetString( cTripwire, tripwire::STR_ERR2_DIFFERENT_USERS1) << dbFile.GetHeader().GetCreator()
|
|
<< TSS_GetString( cTripwire, tripwire::STR_ERR2_DIFFERENT_USERS2) << userName << std::ends;
|
|
cTWUtil::PrintErrorMsg( eICDifferentUsers( str.str(), eError::NON_FATAL ) );
|
|
}
|
|
}
|
|
|
|
// warn if the database is not encrytped
|
|
if(! bDbEncrypted && iUserNotify::GetInstance()->GetVerboseLevel() > iUserNotify::V_SILENT)
|
|
{
|
|
cTWUtil::PrintErrorMsg(eTWDbNotEncrypted(_T(""), eError::NON_FATAL|eError::SUPRESS_THIRD_MSG));
|
|
}
|
|
|
|
if( (!bDbEncrypted) && (mpData->mLocalProvided) )
|
|
{
|
|
//Issue a warning if a passphrase has been supplied, and the database is NOT encrypted.
|
|
cTWUtil::PrintErrorMsg( eTWPassForUnencryptedDb( _T(""), eError::NON_FATAL));
|
|
}
|
|
|
|
|
|
try
|
|
{
|
|
cFileManipulator polManipulator(mpData->mPolFile.c_str());
|
|
polManipulator.Init();
|
|
bPolEncrypted = polManipulator.GetEncoding() == cFileHeader::ASYM_ENCRYPTION;
|
|
}
|
|
catch (eError&) {}
|
|
|
|
//
|
|
// get the passwords for early prompting
|
|
//
|
|
if(! mpData->mbLatePassphrase)
|
|
{
|
|
if(bDbEncrypted)
|
|
cTWUtil::CreatePrivateKey(privateLocal, localKeyfile, mpData->mLocalProvided ? mpData->mLocalPassphrase.c_str() : 0, cTWUtil::KEY_LOCAL);
|
|
|
|
if(bPolEncrypted)
|
|
cTWUtil::CreatePrivateKey(privateSite, siteKeyfile, mpData->mSiteProvided ? mpData->mSitePassphrase.c_str() : 0, cTWUtil::KEY_SITE);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////
|
|
// iterate through all the genres in the new policy...
|
|
/////////////////////////////////////////////////////////
|
|
cFCODatabaseFile::iterator dbIter( dbFile );
|
|
cGenreSpecListVector::iterator genreIter;
|
|
for (genreIter = genreSpecList.begin(); genreIter != genreSpecList.end(); ++genreIter)
|
|
{
|
|
// make this genre the current genre.
|
|
//
|
|
cGenreSwitcher::GetInstance()->SelectGenre( genreIter->GetGenre() );
|
|
//
|
|
// seek the database iter to this genre...
|
|
//
|
|
dbIter.SeekToGenre( genreIter->GetGenre() );
|
|
if( ! dbIter.Done() )
|
|
{
|
|
// perform the policy update
|
|
//
|
|
cPolicyUpdate pu( genreIter->GetGenre(), dbIter.GetSpecList(), genreIter->GetSpecList(), dbIter.GetDb(), pQueue );
|
|
uint32 puFlags = 0;
|
|
puFlags |= mpData->mbAnal ? cPolicyUpdate::ANAL : 0;
|
|
puFlags |= ( mpData->mbResetAccessTime ? cPolicyUpdate::FLAG_ERASE_FOOTPRINTS_PU : 0 );
|
|
if( (! pu.Execute(puFlags)) && (mpData->mbAnal) )
|
|
{
|
|
// they were in anal mode and errors occured; an error condition
|
|
TCOUT << TSS_GetString( cTripwire, tripwire::STR_ERR_POL_UPDATE) << std::endl;
|
|
return 8;
|
|
}
|
|
// we need to update the database's prop set...
|
|
//
|
|
dbIter.GetSpecList() = genreIter->GetSpecList();
|
|
//
|
|
// TODO -- do some header stuff here?
|
|
//
|
|
}
|
|
else
|
|
{
|
|
// do a database init for this genre; it did not appear in the old policy...
|
|
//
|
|
TW_NOTIFY_NORMAL( TSS_GetString( cTripwire, tripwire::STR_PU_ADDING_GENRE ).c_str(),
|
|
cGenreSwitcher::GetInstance()->GenreToString( genreIter->GetGenre(), true ) );
|
|
dbFile.AddGenre( genreIter->GetGenre(), &dbIter );
|
|
|
|
// copy the spec list to the database...
|
|
dbIter.GetSpecList() = genreIter->GetSpecList();
|
|
|
|
// generate the database...
|
|
// TODO -- turn pQueue into an error bucket
|
|
|
|
uint32 gdbFlags = 0;
|
|
gdbFlags |= ( mpData->mbResetAccessTime ? cGenerateDb::FLAG_ERASE_FOOTPRINTS_GD : 0 );
|
|
cGenerateDb::Execute( dbIter.GetSpecList(), dbIter.GetDb(), dbIter.GetGenreHeader().GetPropDisplayer(), pQueue, gdbFlags );
|
|
|
|
//TODO -- what other prop displayer stuff do I have to do here?
|
|
}
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
// now, we need to prune genres that are in the database but not in the new policy...
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
for( dbIter.SeekBegin(); ! dbIter.Done(); )
|
|
{
|
|
bool bFoundGenre = false;
|
|
for (genreIter = genreSpecList.begin(); genreIter != genreSpecList.end(); ++genreIter)
|
|
{
|
|
if( genreIter->GetGenre() == dbIter.GetGenre() )
|
|
{
|
|
bFoundGenre = true;
|
|
break;
|
|
}
|
|
}
|
|
if( ! bFoundGenre )
|
|
{
|
|
// we need to remove this genre from the db...
|
|
//
|
|
dbIter.Remove();
|
|
}
|
|
else
|
|
dbIter.Next() ;
|
|
}
|
|
|
|
|
|
// let's go ahead and update the database and policy file...
|
|
|
|
//
|
|
// open the site key file and get the site passphrase
|
|
//
|
|
if(!privateSite.Valid() && bPolEncrypted)
|
|
cTWUtil::CreatePrivateKey(privateSite, siteKeyfile, mpData->mSiteProvided ? mpData->mSitePassphrase.c_str() : 0, cTWUtil::KEY_SITE);
|
|
//
|
|
// get the passphrase for the database, if necessary (it is important that we get both
|
|
// private keys before saving anything
|
|
//
|
|
if(bDbEncrypted && !privateLocal.Valid())
|
|
{
|
|
ASSERT(mpData->mbLatePassphrase);
|
|
cTWUtil::CreatePrivateKey(privateLocal, localKeyfile, mpData->mLocalProvided ? mpData->mLocalPassphrase.c_str() : 0, cTWUtil::KEY_LOCAL);
|
|
}
|
|
|
|
// backup the file we are about to overwrite
|
|
cFileUtil::BackupFile(mpData->mPolFile);
|
|
|
|
//
|
|
// write the policy file
|
|
//
|
|
cTWUtil::UpdatePolicyFile(mpData->mPolFile.c_str(), mpData->mTextPolFile.c_str(), bPolEncrypted, bPolEncrypted ? privateSite.GetKey() : 0);
|
|
|
|
//
|
|
// update the header info
|
|
//
|
|
// Note: We DO NOT call cFCODatabaseUtil::CalculateHeader() here. We only
|
|
// want to update these entries.
|
|
dbFile.GetHeader().SetCreator(cTWUtil::GetCurrentUser());
|
|
dbFile.GetHeader().SetPolicyFilename(mpData->mPolFile);
|
|
dbFile.GetHeader().SetConfigFilename(mstrConfigFile);
|
|
dbFile.GetHeader().SetLastDBUpdateTime( cSystemInfo::GetExeStartTime() );
|
|
|
|
// backup the file we are about to overwrite
|
|
cFileUtil::BackupFile(mpData->mDbFile);
|
|
|
|
//
|
|
// write the db to disk...
|
|
//
|
|
cTWUtil::WriteDatabase(mpData->mDbFile.c_str(), dbFile, bDbEncrypted, bDbEncrypted ? privateLocal.GetKey() : 0);
|
|
}
|
|
catch(eError& e)
|
|
{
|
|
if (mpData->mbLogToSyslog)
|
|
{
|
|
TSTRING msg = TSS_GetString( cTripwire, tripwire::STR_SYSLOG_POLUP_FAIL_MSG );
|
|
msg.append(cErrorTable::GetInstance()->Get( e.GetID() ));
|
|
|
|
cSyslog::Log(TSS_GetString( cTripwire, tripwire::STR_SYSLOG_IDENT ).c_str(), cSyslog::LOG_ERROR, msg.c_str());
|
|
}
|
|
|
|
cTWUtil::PrintErrorMsg(e);
|
|
return 8;
|
|
}
|
|
|
|
if (mpData->mbLogToSyslog)
|
|
{
|
|
TSTRING msg = TSS_GetString( cTripwire, tripwire::STR_SYSLOG_POLUP_MSG );
|
|
msg.append(mpData->mDbFile);
|
|
cSyslog::Log(TSS_GetString( cTripwire, tripwire::STR_SYSLOG_IDENT ).c_str(), cSyslog::LOG_SUCCESS, msg.c_str());
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// GetModeUsage
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
TSTRING cTWModePolUpdate::GetModeUsage( void )
|
|
{
|
|
return ( TSS_GetString( cTripwire, tripwire::STR_TRIPWIRE_HELP_UPDATE_POLICY ) );
|
|
}
|
|
|
|
//#############################################################################
|
|
// cTWModeTest
|
|
//#############################################################################
|
|
|
|
class cTWModeTest_i : public cTWModeCommon
|
|
{
|
|
public:
|
|
cTWModeTest_i() : cTWModeCommon() { mMode=TEST_INVALID; }
|
|
|
|
enum TestMode { TEST_INVALID, TEST_EMAIL };
|
|
|
|
TestMode mMode;
|
|
TSTRING mEmailAddress;
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// ctor, dtor
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
cTWModeTest::cTWModeTest()
|
|
{
|
|
mpData = new cTWModeTest_i;
|
|
}
|
|
|
|
cTWModeTest::~cTWModeTest()
|
|
{
|
|
delete mpData;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// InitCmdLineParser
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void cTWModeTest::InitCmdLineParser(cCmdLineParser& cmdLine)
|
|
{
|
|
// initialize the switches common to all modes...
|
|
InitCmdLineCommon(cmdLine);
|
|
|
|
// The only allowed test mode syntax so far is
|
|
// "tripwire --test --email name@domain.com" or "tripwire -t -e name@domain.com".
|
|
cmdLine.AddArg(cTWCmdLine::MODE_TEST, TSTRING(_T("")), TSTRING(_T("test")), cCmdLineParser::PARAM_NONE);
|
|
cmdLine.AddArg(cTWCmdLine::TEST_EMAIL, TSTRING(_T("e")), TSTRING(_T("email")), cCmdLineParser::PARAM_ONE);
|
|
|
|
cmdLine.AddDependency( cTWCmdLine::MODE_TEST, cTWCmdLine::TEST_EMAIL );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Init
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool cTWModeTest::Init(const cConfigFile& cf, const cCmdLineParser& cmdLine)
|
|
{
|
|
// first, fill out everything with the config file info...
|
|
FillOutConfigInfo(mpData, cf);
|
|
|
|
// now, parse the command line...
|
|
// this takes care of the common stuff...
|
|
FillOutCmdLineInfo(mpData, cmdLine);
|
|
|
|
cCmdLineIter iter(cmdLine);
|
|
for(iter.SeekBegin(); ! iter.Done(); iter.Next())
|
|
{
|
|
switch(iter.ArgId())
|
|
{
|
|
case cTWCmdLine::TEST_EMAIL:
|
|
mpData->mMode = cTWModeTest_i::TEST_EMAIL;
|
|
mpData->mEmailAddress = iter.ParamAt(0);
|
|
break;
|
|
default:
|
|
// should I do anything, or just ignore this?
|
|
;
|
|
}
|
|
}
|
|
|
|
// make sure that we have a valid operation
|
|
TEST_INIT_REQUIREMENT( ( mpData->mMode != cTWModeTest_i::TEST_INVALID ), cTripwire, tripwire::STR_ERR_NO_TEST_MODE );
|
|
|
|
if( mpData->mMode == cTWModeTest_i::TEST_EMAIL )
|
|
{
|
|
// make sure that we have a valid mail method
|
|
TEST_INIT_REQUIREMENT( ( cMailMessage::NO_METHOD != mpData->mMailMethod ), cTripwire, tripwire::STR_ERR_NO_MAIL_METHOD );
|
|
TEST_INIT_REQUIREMENT( ( cMailMessage::INVALID_METHOD != mpData->mMailMethod ), cTripwire, tripwire::STR_ERR_INVALID_MAIL_METHOD );
|
|
#if !SUPPORTS_MAPI
|
|
TEST_INIT_REQUIREMENT( ( cMailMessage::MAIL_BY_MAPI != mpData->mMailMethod ), cTripwire, tripwire::STR_ERR_MAPI_NOT_SUPPORTED );
|
|
#endif
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Execute
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
int cTWModeTest::Execute(cErrorQueue* pQueue)
|
|
{
|
|
cDebug d("cTWModeTest::Execute");
|
|
|
|
switch (mpData->mMode)
|
|
{
|
|
case cTWModeTest_i::TEST_EMAIL:
|
|
{
|
|
cTWCmdLineUtil::SendEmailTestMessage(mpData->mEmailAddress, mpData);
|
|
}
|
|
default:
|
|
// should I do anything, or just ignore this?
|
|
;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
TSTRING cTWModeTest::GetModeUsage( )
|
|
{
|
|
return ( TSS_GetString( cTripwire, tripwire::STR_TRIPWIRE_HELP_TEST ) );
|
|
}
|
|
|
|
//#############################################################################
|
|
// cTWModeHelp
|
|
//#############################################################################
|
|
|
|
class cTWModeHelp_i : public cTWModeCommon
|
|
{
|
|
public:
|
|
cTWModeHelp_i() {}
|
|
~cTWModeHelp_i() {}
|
|
|
|
std::set< TSTRING > mModes;
|
|
// A set of modes to output usage statements for a specific mode.
|
|
std::set< TSTRING > mPrinted;
|
|
// A set for making sure we don't print the same help twice.
|
|
};
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// ctor, dtor
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
cTWModeHelp::cTWModeHelp()
|
|
{
|
|
mpData = new cTWModeHelp_i();
|
|
}
|
|
|
|
cTWModeHelp::~cTWModeHelp()
|
|
{
|
|
delete mpData;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// InitCmdLineParser
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void cTWModeHelp::InitCmdLineParser(cCmdLineParser& cmdLine)
|
|
{
|
|
// We're only interested in one parameter, that being help. Anything else
|
|
// passed to this mode should be a cmdlineparser error.
|
|
cmdLine.AddArg(cTWCmdLine::MODE, TSTRING(_T("m")), TSTRING(_T("")), cCmdLineParser::PARAM_MANY, true);
|
|
cmdLine.AddArg(cTWCmdLine::MODE_HELP, TSTRING(_T("?")), TSTRING(_T("help")), cCmdLineParser::PARAM_MANY);
|
|
cmdLine.AddArg(cTWCmdLine::MODE_HELP_ALL, TSTRING(_T("")), TSTRING(_T("all")), cCmdLineParser::PARAM_MANY);
|
|
cmdLine.AddArg(cTWCmdLine::MODE_INIT, TSTRING(_T("i")), TSTRING(_T("init")), cCmdLineParser::PARAM_MANY);
|
|
cmdLine.AddArg(cTWCmdLine::MODE_CHECK, TSTRING(_T("c")), TSTRING(_T("check")), cCmdLineParser::PARAM_MANY);
|
|
cmdLine.AddArg(cTWCmdLine::MODE_UPDATE_DB, TSTRING(_T("u")), TSTRING(_T("update")), cCmdLineParser::PARAM_MANY);
|
|
cmdLine.AddArg(cTWCmdLine::MODE_UPDATE_POL, TSTRING(_T("p")), TSTRING(_T("update-policy")), cCmdLineParser::PARAM_MANY);
|
|
cmdLine.AddArg(cTWCmdLine::MODE_TEST, TSTRING(_T("t")), TSTRING(_T("test")), cCmdLineParser::PARAM_MANY);
|
|
cmdLine.AddArg(cTWCmdLine::MODE_EXPLORE, TSTRING(_T("")), TSTRING(_T("explore")), cCmdLineParser::PARAM_MANY);
|
|
cmdLine.AddArg(cTWCmdLine::MODE_DEBUG, TSTRING(_T("")), TSTRING(_T("verify")), cCmdLineParser::PARAM_MANY);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Init
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool cTWModeHelp::Init(const cConfigFile& cf, const cCmdLineParser& cmdLine)
|
|
{
|
|
cCmdLineIter iter(cmdLine);
|
|
|
|
// Grab the arguments from the help parameter:
|
|
for(iter.SeekBegin(); ! iter.Done(); iter.Next())
|
|
{
|
|
switch(iter.ArgId())
|
|
{
|
|
case cTWCmdLine::MODE_HELP:
|
|
{
|
|
int i;
|
|
for( i = 0; i < iter.NumParams(); ++i )
|
|
{
|
|
mpData->mModes.insert( iter.ParamAt(i) );
|
|
}
|
|
}
|
|
break;
|
|
case cTWCmdLine::MODE:
|
|
{
|
|
int i;
|
|
for( i = 0; i < iter.NumParams(); ++i )
|
|
{
|
|
mpData->mModes.insert( iter.ParamAt(i) );
|
|
}
|
|
}
|
|
break;
|
|
// allow users to enter the mode
|
|
// names with "--" prepended. We have to do this, since
|
|
// the cmdlineparser treats them as switches.
|
|
case cTWCmdLine::MODE_HELP_ALL: // fall through
|
|
case cTWCmdLine::MODE_INIT: // fall through
|
|
case cTWCmdLine::MODE_CHECK: // fall through
|
|
case cTWCmdLine::MODE_UPDATE_DB: // fall through
|
|
case cTWCmdLine::MODE_UPDATE_POL: // fall through
|
|
case cTWCmdLine::MODE_TEST: // fall through
|
|
case cTWCmdLine::MODE_EXPLORE: // fall through
|
|
case cTWCmdLine::MODE_DEBUG:
|
|
{
|
|
int i;
|
|
// push back the parameter that was actually passed.
|
|
TSTRING str = iter.ActualParam();
|
|
// Kill off the initial "--" or "-"
|
|
str.erase( 0, 1 );
|
|
if( str.length() != 1)
|
|
str.erase( 0, 1 );
|
|
|
|
mpData->mModes.insert( str );
|
|
for( i = 0; i < iter.NumParams(); ++i )
|
|
mpData->mModes.insert( iter.ParamAt(i) );
|
|
}
|
|
break;
|
|
default:
|
|
// should I do anything, or just ignore this?
|
|
// cmdlineparser will catch the bad args.
|
|
;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Execute
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
int cTWModeHelp::Execute(cErrorQueue* pQueue)
|
|
{
|
|
cDebug d("cTWModeHelp::Execute");
|
|
|
|
// The iterator we will use to traverse the list of arguments:
|
|
std::set<TSTRING>::iterator it = mpData->mModes.begin();
|
|
|
|
// We'll want to output the version information, regardless:
|
|
TCOUT << TSS_GetString( cTripwire, tripwire::STR_TRIPWIRE_VERSION) << std::endl;
|
|
TCOUT << TSS_GetString( cTW, tw::STR_VERSION) << std::endl;
|
|
|
|
if( it == mpData->mModes.end() ) // all that was passed was --help
|
|
{
|
|
// Output a short usage summary for each mode.
|
|
TCOUT << TSS_GetString( cTripwire, tripwire::STR_TRIPWIRE_USAGE_SUMMARY );
|
|
//
|
|
// That's it, return.
|
|
return 8;
|
|
}
|
|
|
|
for( ; it != mpData->mModes.end(); ++it )
|
|
{
|
|
if( _tcscmp( (*it).c_str(), _T("all")) == 0 )
|
|
{
|
|
//Since --help all was passed, emit all help messages and return.
|
|
TCOUT<< TSS_GetString( cTripwire, tripwire::STR_TRIPWIRE_HELP_INIT );
|
|
TCOUT<< TSS_GetString( cTripwire, tripwire::STR_TRIPWIRE_HELP_CHECK );
|
|
TCOUT<< TSS_GetString( cTripwire, tripwire::STR_TRIPWIRE_HELP_UPDATE );
|
|
TCOUT<< TSS_GetString( cTripwire, tripwire::STR_TRIPWIRE_HELP_UPDATE_POLICY );
|
|
TCOUT<< TSS_GetString( cTripwire, tripwire::STR_TRIPWIRE_HELP_TEST );
|
|
#ifdef _DEBUG_DB
|
|
// TODO: Do we need help messages for these modes? DRA
|
|
#endif
|
|
//We're done, return
|
|
return 8;
|
|
}
|
|
}
|
|
|
|
//We need some subset of the usage statements. Figure out which modes have
|
|
//been specified:
|
|
it = mpData->mModes.begin();
|
|
for( ; it != mpData->mModes.end(); ++it )
|
|
{
|
|
// This is going to be ugly code...
|
|
if ( _tcscmp( (*it).c_str(), _T("init") ) == 0 || _tcscmp( (*it).c_str(), _T("i") ) == 0 )
|
|
{
|
|
//make sure we don't print the same help twice...
|
|
if( mpData->mPrinted.find( _T("init") ) == mpData->mPrinted.end() )
|
|
{
|
|
TCOUT<< TSS_GetString( cTripwire, tripwire::STR_TRIPWIRE_HELP_INIT );
|
|
mpData->mPrinted.insert( _T("init") );
|
|
}
|
|
}
|
|
else if( _tcscmp( (*it).c_str(), _T("check") ) == 0 || _tcscmp( (*it).c_str(), _T("c") ) == 0 )
|
|
{
|
|
if( mpData->mPrinted.find( _T("check") ) == mpData->mPrinted.end() )
|
|
{
|
|
TCOUT<< TSS_GetString( cTripwire, tripwire::STR_TRIPWIRE_HELP_CHECK );
|
|
mpData->mPrinted.insert( _T("check") );
|
|
}
|
|
}
|
|
else if( _tcscmp( (*it).c_str(), _T("update") ) == 0 || _tcscmp( (*it).c_str(), _T("u") ) == 0 )
|
|
{
|
|
if( mpData->mPrinted.find( _T("update") ) == mpData->mPrinted.end() )
|
|
{
|
|
TCOUT<< TSS_GetString( cTripwire, tripwire::STR_TRIPWIRE_HELP_UPDATE );
|
|
mpData->mPrinted.insert( _T("update") );
|
|
}
|
|
}
|
|
else if( _tcscmp( (*it).c_str(), _T("update-policy") ) == 0 || _tcscmp( (*it).c_str(), _T("p") ) == 0 )
|
|
{
|
|
if( mpData->mPrinted.find( _T("update-policy") ) == mpData->mPrinted.end() )
|
|
{
|
|
TCOUT<< TSS_GetString( cTripwire, tripwire::STR_TRIPWIRE_HELP_UPDATE_POLICY );
|
|
mpData->mPrinted.insert( _T("update-policy") );
|
|
}
|
|
}
|
|
else if( _tcscmp( (*it).c_str(), _T("test") ) == 0 || _tcscmp( (*it).c_str(), _T("t") ) == 0 )
|
|
{
|
|
if( mpData->mPrinted.find( _T("test") ) == mpData->mPrinted.end() )
|
|
{
|
|
TCOUT<< TSS_GetString( cTripwire, tripwire::STR_TRIPWIRE_HELP_TEST );
|
|
mpData->mPrinted.insert( _T("test") );
|
|
}
|
|
}
|
|
else if( _tcscmp( (*it).c_str(), _T("explore") ) == 0 )
|
|
TCOUT<< _T(""); //we currently don't have usage statements for this mode.
|
|
else if( _tcscmp( (*it).c_str(), _T("verify") ) == 0 )
|
|
TCOUT<< _T(""); //we currently don't have usage statements for this mode.
|
|
else
|
|
{
|
|
cTWUtil::PrintErrorMsg( eTWHelpInvalidModeSwitch((*it), eError::NON_FATAL) );
|
|
TCOUT << std::endl;
|
|
// emit error string, this mode does not exist
|
|
}
|
|
}
|
|
|
|
//Everything went okay
|
|
return 8;
|
|
}
|
|
|
|
//================================================================
|
|
// UTIL FUNCTIONS
|
|
//================================================================
|
|
|
|
bool util_GetEditor( TSTRING& strEd )
|
|
{
|
|
// see if VISUAL environment var is set
|
|
TCHAR* pchEd = _tgetenv( _T("VISUAL") );
|
|
if( pchEd != NULL && pchEd[0] != _T('\0') )
|
|
{
|
|
strEd = pchEd;
|
|
return true;
|
|
}
|
|
|
|
// see if EDITOR environment var is set
|
|
pchEd = _tgetenv( _T("EDITOR") );
|
|
if( pchEd != NULL && pchEd[0] != _T('\0') )
|
|
{
|
|
strEd = pchEd;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//Encase the explore and debug modes in this ifdef, since they are for internal
|
|
//use only.
|
|
#ifdef _DEBUG_DB
|
|
|
|
//#############################################################################
|
|
// cTWModeExploreDb
|
|
//#############################################################################
|
|
#include "tw/dbexplore.h"
|
|
|
|
class cTWModeExploreDb_i : public cTWModeCommon
|
|
{
|
|
public:
|
|
cTWModeExploreDb_i() : cTWModeCommon() {}
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// ctor, dtor
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
cTWModeExploreDb::cTWModeExploreDb()
|
|
{
|
|
mpData = new cTWModeExploreDb_i;
|
|
}
|
|
|
|
cTWModeExploreDb::~cTWModeExploreDb()
|
|
{
|
|
delete mpData;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// InitCmdLineParser
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void cTWModeExploreDb::InitCmdLineParser(cCmdLineParser& cmdLine)
|
|
{
|
|
// initialize the switches common to all modes...
|
|
InitCmdLineCommon(cmdLine);
|
|
|
|
cmdLine.AddArg(cTWCmdLine::MODE_EXPLORE, TSTRING(_T("")), TSTRING(_T("explore")), cCmdLineParser::PARAM_NONE);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Init
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool cTWModeExploreDb::Init(const cConfigFile& cf, const cCmdLineParser& cmdLine)
|
|
{
|
|
// first, fill out everything with the config file info...
|
|
FillOutConfigInfo(mpData, cf);
|
|
|
|
// now, parse the command line...
|
|
// this takes care of the common stuff...
|
|
FillOutCmdLineInfo(mpData, cmdLine);
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Execute
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
int cTWModeExploreDb::Execute(cErrorQueue* pQueue)
|
|
{
|
|
cDebug d("cTWModeExploreDb::Execute");
|
|
|
|
cFCODatabaseFile dbFile;
|
|
cFCODatabaseFile::iterator dbIter( dbFile );
|
|
try
|
|
{
|
|
cKeyFile localKeyfile;
|
|
cTWUtil::OpenKeyFile(localKeyfile, mpData->mLocalKeyFile);
|
|
|
|
bool bEncrypted;
|
|
cTWUtil::ReadDatabase(mpData->mDbFile.c_str(), dbFile, localKeyfile.GetPublicKey(), bEncrypted);
|
|
//
|
|
// seek to the first genre in the db...
|
|
//
|
|
dbIter.SeekBegin();
|
|
if( dbIter.Done() )
|
|
{
|
|
//TODO -- what is the right thing to do here?
|
|
//
|
|
ASSERT( false );
|
|
throw eTWDbHasNoGenres();
|
|
}
|
|
//
|
|
// ok, time to explore the database!
|
|
//
|
|
cDbExplore::Execute( dbIter );
|
|
}
|
|
catch(eError& e)
|
|
{
|
|
cTWUtil::PrintErrorMsg(e);
|
|
return 8;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//#############################################################################
|
|
// cTWModeDebugDb
|
|
//#############################################################################
|
|
#include "tw/dbdebug.h"
|
|
|
|
class cTWModeDebugDb_i : public cTWModeCommon
|
|
{
|
|
public:
|
|
cTWModeDebugDb_i() : cTWModeCommon() {}
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// ctor, dtor
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
cTWModeDebugDb::cTWModeDebugDb()
|
|
{
|
|
mpData = new cTWModeDebugDb_i;
|
|
}
|
|
|
|
cTWModeDebugDb::~cTWModeDebugDb()
|
|
{
|
|
delete mpData;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// InitCmdLineParser
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
void cTWModeDebugDb::InitCmdLineParser(cCmdLineParser& cmdLine)
|
|
{
|
|
// initialize the switches common to all modes...
|
|
InitCmdLineCommon(cmdLine);
|
|
|
|
cmdLine.AddArg(cTWCmdLine::MODE_DEBUG, TSTRING(_T("")), TSTRING(_T("verifydb")), cCmdLineParser::PARAM_NONE);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Init
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
bool cTWModeDebugDb::Init(const cConfigFile& cf, const cCmdLineParser& cmdLine)
|
|
{
|
|
// first, fill out everything with the config file info...
|
|
FillOutConfigInfo(mpData, cf);
|
|
|
|
// now, parse the command line...
|
|
// this takes care of the common stuff...
|
|
FillOutCmdLineInfo(mpData, cmdLine);
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Execute
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
int cTWModeDebugDb::Execute(cErrorQueue* pQueue)
|
|
{
|
|
cDebug d("cTWModeDebugDb::Execute");
|
|
|
|
cFCODatabaseFile dbFile;
|
|
cFCODatabaseFile::iterator dbIter( dbFile );
|
|
try
|
|
{
|
|
cKeyFile localKeyfile;
|
|
cTWUtil::OpenKeyFile(localKeyfile, mpData->mLocalKeyFile);
|
|
|
|
bool bEncrypted;
|
|
cTWUtil::ReadDatabase(mpData->mDbFile.c_str(), dbFile, localKeyfile.GetPublicKey(), bEncrypted);
|
|
//
|
|
// seek to the first genre in the db...
|
|
//
|
|
dbIter.SeekBegin();
|
|
if( dbIter.Done() )
|
|
{
|
|
//TODO -- what is the right thing to do here?
|
|
//
|
|
ASSERT( false );
|
|
throw eTWDbHasNoGenres();
|
|
}
|
|
//
|
|
// debug the database.
|
|
//
|
|
cDbDebug::Execute( dbIter, mpData->mDbFile );
|
|
}
|
|
catch(eError& e)
|
|
{
|
|
cTWUtil::PrintErrorMsg(e);
|
|
return 8;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
#endif //_DEBUG_DB
|
|
|
|
|