tripwire-open-source/src/siggen/siggencmdline.cpp

375 lines
13 KiB
C++

//
// The developer of the original code and/or files is Tripwire, Inc.
// Portions created by Tripwire, Inc. are copyright (C) 2000-2017 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.
//
//siggencmdline.cpp
#include "stdsiggen.h"
#include "siggencmdline.h"
#include "core/cmdlineparser.h"
#include "core/archive.h" // cArchive and friends
#include "fco/signature.h" // cSignature
#include "fs/fsstrings.h" // file system related strings
#include "core/usernotify.h" // for notifying the user of events
#include "core/errorbucketimpl.h" // for the error table
#include "core/fsservices.h"
#include "tw/twstrings.h"
#include "core/displayencoder.h"
#include "siggenstrings.h"
#include <fstream> // for the FileExists() stuff
#include <unistd.h>
#include <fcntl.h>
#if SUPPORTS_TERMIOS
# include <termios.h>
# include <sys/ioctl.h>
#endif
//#include <signal.h>
int _getch(void);
using namespace std;
///////////////////////////////////////////////////////////////////////////////
// Static Functions, Variables --
///////////////////////////////////////////////////////////////////////////////
static void PrintHeader(TSTRING filename);
static bool util_FileExists(const TSTRING &fileName);
//=========================================================================
// GLOBALS
//=========================================================================
const TCHAR* g_szEightyDashes = _T("--------------------------------------------------------------------------------");
///////////////////////////////////////////////////////////////////////////////
//Insulated implementation for cSiggenCmdLine
struct cSiggen_i
{
cSiggen_i() : mPrintHex(false), mTerseOutput(false) {}
~cSiggen_i();
//Data Members:
bool mPrintHex;
//If this is true, the signatures will be output in hex rather than Base64
bool mTerseOutput;
//If this is true, only the signatures will be printed, and the output will only use one line.
typedef std::list<std::pair< iSignature*, TSTRING> > ListType;
ListType mSignatures;
std::list<TSTRING> mFilesToCheck;
//A list of the files that need signatures generated for them.
};
//Dtor:
cSiggen_i::~cSiggen_i()
{
cSiggen_i::ListType::iterator i;
//Delete all the dynamically allocated signature objects.
for (i = mSignatures.begin(); i != mSignatures.end(); ++i) {
if ( ((*i).first) != NULL)
delete ((*i).first);
}
}
//#############################################################################
// cSiggenCmdLine
//#############################################################################
cSiggenCmdLine::cSiggenCmdLine()
{
mpData = new cSiggen_i;
}
cSiggenCmdLine::~cSiggenCmdLine()
{
delete mpData;
}
///////////////////////////////////////////////////////////////////////////////
// InitCmdLineParser -- Make the command line cognizant of siggen's arguments
///////////////////////////////////////////////////////////////////////////////
void cSiggenCmdLine::InitCmdLineParser(cCmdLineParser& parser)
{
parser.AddArg(HELP, TSTRING(_T("?")), TSTRING(_T("help")), cCmdLineParser::PARAM_NONE) ;
//Signatures:
parser.AddArg(CRC32, TSTRING(_T("C")), TSTRING(_T("CRC32")), cCmdLineParser::PARAM_NONE);
parser.AddArg(MD5, TSTRING(_T("M")), TSTRING(_T("MD5")), cCmdLineParser::PARAM_NONE);
parser.AddArg(SHA, TSTRING(_T("S")), TSTRING(_T("SHA")), cCmdLineParser::PARAM_NONE);
parser.AddArg(HAVAL, TSTRING(_T("H")), TSTRING(_T("HAVAL")), cCmdLineParser::PARAM_NONE);
//Output switches
parser.AddArg(ALL, TSTRING(_T("a")), TSTRING(_T("all")), cCmdLineParser::PARAM_NONE);
parser.AddArg(HEX, TSTRING(_T("h")), TSTRING(_T("hexadecimal")), cCmdLineParser::PARAM_NONE);
parser.AddArg(TERSE, TSTRING(_T("t")), TSTRING(_T("terse")), cCmdLineParser::PARAM_NONE);
//file parameters
parser.AddArg(PARAMS, TSTRING(_T("")), TSTRING(_T("")), cCmdLineParser::PARAM_MANY);
}
int cSiggenCmdLine::Execute()
{
cFileArchive arch;
//archive for reading in files
TCOUT.flags( ( TCOUT.flags() & ~std::ios::adjustfield ) | std::ios::left );
//align all output to the left.
int rtn = 0;
// return value -- by default, it is set to 0 (OK)
//Check to see if files have been specified.
if(mpData->mFilesToCheck.empty())
return 0;
//Iterate over file list and generate each signature:
std::list<TSTRING>::iterator fileIter;
for (fileIter = mpData->mFilesToCheck.begin(); fileIter != mpData->mFilesToCheck.end(); ++fileIter)
{
cDisplayEncoder e;
TSTRING displayStr = *fileIter;
e.Encode(displayStr);
if(!mpData->mTerseOutput)
PrintHeader( displayStr );
if( ! util_FileExists( *fileIter ) )
{
TCOUT << TSS_GetString( cSiggen, siggen::STR_ERR_NO_FILE ) << _T(": ") << displayStr.c_str() <<endl;
rtn = 1;
continue;
}
//
// ignore this if it is not a plain file...
//
cFSStatArgs fileInfo;
try
{
iFSServices::GetInstance()->Stat(*fileIter, fileInfo);
if(fileInfo.mFileType != cFSStatArgs::TY_FILE)
{
// Not a regular file; warn and skip this file.
//
TCOUT << displayStr << TSS_GetString( cSiggen, siggen::STR_SIGGEN_NOT_REG_FILE ) << std::endl;
rtn = 1;
continue;
}
}
catch(eFSServices& e)
{
cErrorReporter::PrintErrorMsg(e);
rtn = 1;
continue;
}
//Prepare the archive for reading from current file (in loop).
try
{
arch.OpenRead( (*fileIter).c_str() );
}
catch (eArchive&)
{
TCOUT << TSS_GetString( cSiggen, siggen::STR_ERR_OPEN_FAILED ) << _T(": ") << displayStr.c_str() <<endl;
rtn = 1;
continue;
}
//
// Iterate over the <signature, signature name> list and add each signature to the
// sig generator
//
cArchiveSigGen asg;
std::list< std::pair<iSignature*, TSTRING> >::iterator sigIter;
for ( sigIter = mpData->mSignatures.begin(); sigIter!= mpData->mSignatures.end(); ++sigIter )
asg.AddSig( (*sigIter).first );
//
// calculate signatures
//
arch.Seek(0, cBidirArchive::BEGINNING);
asg.CalculateSignatures( arch );
arch.Close();
//
// Iterate over the <signature, signature name> list and output each signature:
//
for ( sigIter = mpData->mSignatures.begin(); sigIter != mpData->mSignatures.end(); ++sigIter )
{
if(!mpData->mTerseOutput)
TCOUT.width(20);
//Set the output string to Hex or Base64, depending on the value of mPrintHex
TSTRING sigStringOut;
if (mpData->mPrintHex)
sigStringOut = ((*sigIter).first)->AsStringHex();
else
sigStringOut = ((*sigIter).first)->AsString();
//Output the signatures, include identifiers and newlines only if mTerseOutput is false.
if(!mpData->mTerseOutput)
TCOUT << (*sigIter).second.c_str();
TCOUT << sigStringOut;
if(!mpData->mTerseOutput)
TCOUT << endl;
else
TCOUT << _T(" ");
//Output finished for iteration
}//end for
//Seperate lines of signatures (for multiple files) with a newline (if terse output)
if(mpData->mTerseOutput)
TCOUT << endl;
}
if(!mpData->mTerseOutput)
TCOUT << g_szEightyDashes << _T("\n");
return rtn;
}
//Interprets the parsed command line and sets the member variables necessary for correct output.
//See cSiggen_i.
//Returns 0 if no file parameters have been passed, otherwise, returns 1.
int cSiggenCmdLine::Init(cCmdLineParser& parser)
{
cCmdLineIter iter(parser); //iterator for traversing command line
iter.SeekBegin();
int i = 0; //loop variable
bool crc_select = false, md5_select = false, sha_select = false, haval_select = false;
//boolean locals for dealing with ALL switch. (temp.?) fix -DA
bool switch_present = false;
int ret = 0; //return value. will be false unless some file is specified.
for(iter.SeekBegin(); ! iter.Done(); iter.Next())
{
switch(iter.ArgId())
{
case HELP:
{
return 0;
}
case CRC32:
{
crc_select = switch_present = true;
break;
}
case MD5:
{
md5_select = switch_present = true;
break;
}
case SHA:
{
sha_select = switch_present = true;
break;
}
case HAVAL:
{
haval_select = switch_present = true;
break;
}
case ALL:
{
crc_select = md5_select = sha_select = haval_select = switch_present = true;
break;
}
case HEX:
{
mpData->mPrintHex = true;
break;
}
case TERSE:
{
mpData->mTerseOutput = true;
break;
}
case PARAMS:
{
ret |= 1;
for (; i < iter.NumParams(); ++i) {
mpData->mFilesToCheck.push_back(TSTRING (iter.ParamAt(i)) );
}
}
default:
break;
}
}
//Default behavior is to print all signatures if no switch is specified.
if(!switch_present)
crc_select = md5_select = sha_select = haval_select = true;
//Push the signatures and their output identifiers onto the mSignature list:
if(crc_select)
{
iSignature* sig_ptr = new cCRC32Signature;
TSTRING str = TSS_GetString( cFS, fs::STR_PROP_CRC32);
mpData->mSignatures.push_back(std::pair< iSignature*, TSTRING>(sig_ptr, str));
}
if(md5_select)
{
iSignature* sig_ptr = new cMD5Signature;
TSTRING str = TSS_GetString( cFS, fs::STR_PROP_MD5);
mpData->mSignatures.push_back(std::pair< iSignature*, TSTRING>(sig_ptr, str));
}
if(sha_select)
{
iSignature* sig_ptr = new cSHASignature;
TSTRING str = TSS_GetString( cFS, fs::STR_PROP_SHA);
mpData->mSignatures.push_back(std::pair< iSignature*, TSTRING>(sig_ptr, str));
}
if(haval_select)
{
iSignature* sig_ptr = new cHAVALSignature;
TSTRING str = TSS_GetString( cFS, fs::STR_PROP_HAVAL);
mpData->mSignatures.push_back(std::pair< iSignature*, TSTRING>(sig_ptr, str));
}
return ret;
}
//Prints a header for each signature.
void PrintHeader( TSTRING filename)
{
TCOUT << g_szEightyDashes << _T( "\n" );
TCOUT << _T("Signatures for file: ") << filename.c_str() << _T("\n\n");
}
bool util_FileExists(const TSTRING& fileName)
{
return _taccess(fileName.c_str(), F_OK) == 0;
}