//
// $Id: Common.cpp,v 1.2 2004/06/24 14:17:21 bakerj Exp $
//
//************************** Property of the MITRE Corporation ***************************//
//
// Copyright (c) 2003 - The MITRE Corporation
//
// This file is part of the OVAL Query Interpreter.
//
// The OVAL Query Interpreter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License.
//
// The OVAL Query Interpreter is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with the OVAL
// Query Interpreter; if not, write to the Free Software Foundation, Inc., 59 Temple
// Place, Suite 330, Boston, MA 02111-1307 USA
//
//****************************************************************************************//

#include "Common.h"

// Initialize static variables.

string	Common::database		= "data.slt";
string	Common::datafile		= "definitions.sql";
string	Common::datafileMD5		= "";
string	Common::outputFilename	= "results.html";	
string	Common::startTime		= "";
int		Common::outputFiletype	= 2;	
bool	Common::generateMD5		= false;
bool	Common::outputToFile	= true;				
bool	Common::useExistingData	= false;
bool	Common::verifyDatafile	= true;
sqlite*	Common::ptrSQLiteDB		= NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  Accessors  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//

string Common::GetDatafile()
{
	return datafile;	
}

string Common::GetDatafileMD5()
{
	return datafileMD5;	
}

string Common::GetDatabase()
{
	return database;	
}

bool Common::GetGenerateMD5()
{
	return generateMD5;	
}


string Common::GetOutputFilename()
{
	return outputFilename;	
}

int Common::GetOutputFiletype()
{
	return outputFiletype;	
}

bool Common::GetOutputToFile()
{
	return outputToFile;	
}

string Common::GetStartTime()
{
	return startTime;
}

bool Common::GetUseExistingData()
{
	return useExistingData;
}

bool Common::GetVerifyDatafile()
{
	return verifyDatafile;	
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  Mutators  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//

void Common::SetDatafile(string datafileIn)
{
	datafile = datafileIn;
}

void Common::SetDatafileMD5(string datafileMD5In)
{
	datafileMD5 = datafileMD5In;
}

void Common::SetDatabase(string databaseIn)
{
	database = databaseIn;
}

void Common::SetGenerateMD5(bool genMD5In)
{
	generateMD5 = genMD5In;
}


void Common::SetOutputFilename(string outputFilenameIn)
{
	outputFilename = outputFilenameIn;
}

void Common::SetOutputFiletype(int outputFiletypeIn)
{
	outputFiletype = outputFiletypeIn;
}

void Common::SetOutputToFile(bool outputToFileIn)
{
	outputToFile = outputToFileIn;
}

void Common::SetStartTime(string startTimeIn)
{
	startTime = startTimeIn;
}

void Common::SetUseExistingData(bool useExistingdataIn)
{
	useExistingData = useExistingdataIn;
}
void Common::SetVerifyDatafile(bool verifyDatafileIn)
{
	verifyDatafile = verifyDatafileIn;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  Public Members  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
#ifdef WIN32
	bool Common::DisableAllPrivileges()
	{
		//------------------------------------------------------------------------------------//
		//
		//  ABSTRACT
		//
		//  This function disables all the privileges associated with the current proces
		//  token.  If a specific privilege is needed later, it can be enabled by calling
		//  AdjustTokenPrivileges() again.
		//
		//------------------------------------------------------------------------------------//

		HANDLE hToken = NULL;

		// Get a handle to the current process.

		if (OpenProcessToken(GetCurrentProcess(),						// handle to the process
							 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,		// requested access types 
							 &hToken) == FALSE)							// new access token 
		{
			char buffer[33];
			_itoa(GetLastError(), buffer, 10);

			string errorMessage = "";
			errorMessage.append("\nERROR: Unable to get a handle to the current process.  Error # - ");
			errorMessage.append(buffer);
			errorMessage.append("\n");
			cerr << errorMessage;
			Log::WriteLog(errorMessage);

			return false;
		}

		// Disable all the privileges for this token.

		if (AdjustTokenPrivileges(hToken,					// handle to token
								  TRUE,						// disabling option
								  NULL,						// privilege information
								  0,						// size of buffer
								  NULL,						// original state buffer
								  NULL) == FALSE)			// required buffer size
		{
			char buffer[33];
			_itoa(GetLastError(), buffer, 10);

			string errorMessage = "";
			errorMessage.append("\nERROR: Unable to disable token privileges.  Error # - ");
			errorMessage.append(buffer);
			errorMessage.append("\n");
			cerr << errorMessage;
			Log::WriteLog(errorMessage);

			CloseHandle(hToken);
			return false;
		}

		CloseHandle(hToken);

		return true;
	}

	bool Common::EnablePrivilege(string privilegeIn)
	{
		//------------------------------------------------------------------------------------//
		//
		//  ABSTRACT
		//
		//  This gives us a privilege.
		//
		//------------------------------------------------------------------------------------//

		TOKEN_PRIVILEGES tp;
		HANDLE hProcess = NULL;
		HANDLE hAccessToken = NULL;

		hProcess = GetCurrentProcess();

		if(!OpenProcessToken(hProcess,(TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES),&hAccessToken))
		{
			return false;
		}

		tp.PrivilegeCount = 1;
		tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    
		if (LookupPrivilegeValue(NULL, privilegeIn.c_str(), &tp.Privileges[0].Luid) == 0)
		{
			return false;
		}

		if (AdjustTokenPrivileges(hAccessToken, FALSE, &tp, NULL, NULL, NULL) == 0)
		{
			return false;
		}
		 
		if(GetLastError() == ERROR_NOT_ALL_ASSIGNED)
		{
			// The token for the current process does not have the privilege specified. The
			// AdjustTokenPrivileges() function may succeed with this error value even if no
			// privileges were adjusted.  The privilege parameter can specify privileges that
			// the token does not have, without causing the function to fail. In this case, 
			// the function adjusts the privileges that the token does have and ignores the 
			// other privileges so that the function succeeds.

			CloseHandle(hAccessToken);
			return false;
		}
		else
		{
			CloseHandle(hAccessToken);
			return true;
		}
	}
#endif

string Common::FixQuotes(string stringIn)
{
	//------------------------------------------------------------------------------------//
	//
	//  ABSTRACT
	//
	//  This function takes a string and searches for all ' characters.  If one is found,
	//  another ' is added just before it to act as an escape character.  This is needed
	//  to validate SQL queries.  For example, the following query would cause an error
	//
	//              INSERT INTO table1 VALUES('Hi y'all')
	//
	//  In order to insert the data "Hi y'all" the following SQL statement would need to
	//  be built:
	//
	//              INSERT INTO table1 VALUES('Hi y''all')
	//
	//  NOTE: Is adding a second single quote characeter the only way to escape "'" for
	//  SQLite?  If others are found, we could be open for an SQL injection vulnerability.
	//
	//------------------------------------------------------------------------------------//

	string fixedString = stringIn;

	unsigned int pos = fixedString.find("'", 0);
	while (pos != string::npos)
	{
		fixedString.insert(pos, "'");
		pos = fixedString.find("'", pos+2);
	}

	return fixedString;
}

string Common::FixSlashes(string stringIn)
{
	//------------------------------------------------------------------------------------//
	//
	//  ABSTRACT
	//
	//  This function takes a string and searches for all / characters.  If one is found,
	//  it is replaced with a \.  This is needed by the metabase probe to change the path
	//  strings to look correctly for the OVAL queries.
	//
	//------------------------------------------------------------------------------------//

	string fixedString = stringIn;

	unsigned int pos = fixedString.find("/", 0);
	while (pos != string::npos)
	{
		fixedString.erase(pos, 1);
		fixedString.insert(pos, "\\");
		pos = fixedString.find("/", pos+1);
	}

	return fixedString;
}
#ifdef WIN32
bool Common::GetTextualSid(PSID pSid, LPTSTR* TextualSid)
{ 
	//------------------------------------------------------------------------------------//
	//
	//  ABSTRACT
	//
	//  A SID value includes components that provide information about the SID structure
	//  and components that uniquely identify a trustee. A SID consists of the following
	//  components: 
	//
	//   * The revision level of the SID structure 
	//   * A 48-bit identifier authority value that identifies the authority that issued
	//     the SID 
	//   * A variable number of subauthority or relative identifier (RID) values that
	//     uniquely identify the trustee relative to the authority that issued the SID
	//
	//  The combination of the identifier authority value and the subauthority values
	//  ensures that no two SIDs will be the same, even if two different SID-issuing
	//  authorities issue the same combination of RID values. Each SID-issuing authority
	//  issues a given RID only once. 
	//
	//  SIDs are stored in binary format in a SID structure. To display a SID, you can
	//  call the ConvertSidToStringSid function to convert a binary SID to string format.
	//  To convert a SID string back to a valid, functional SID, call the
	//  ConvertStringSidToSid function. 
	//
	//  These functions use the following standardized string notation for SIDs, which
	//  makes it simpler to visualize their components: 
	//
	//  S-R-I-S-S...
	//
	//  In this notation, the literal character S identifies the series of digits as a
	//  SID, R is the revision level, I is the identifier-authority value, and S... is one
	//  or more subauthority values. 
	//
	//  NOTE:
	//
	//  Windows 2000 provides the ConvertSidToStringSid and ConvertStringSidToSid functions
	//  for converting a SID to and from string format. For a description of the SID string
	//  format, see SID Components.
	//
	//  On earlier versions of Windows NT, use the following sample code to convert a SID
	//  to string format.
	//
	//------------------------------------------------------------------------------------//

    PSID_IDENTIFIER_AUTHORITY psia;
    DWORD dwSubAuthorities;
    DWORD dwSidRev = SID_REVISION;
    DWORD dwCounter;
    DWORD dwSidSize;

    // Validate the binary SID.

	if(!IsValidSid(pSid)) return false;

    // Get the identifier authority value from the SID.
	
	psia = GetSidIdentifierAuthority(pSid);

	// Get the number of subauthorities in the SID.

    dwSubAuthorities = *GetSidSubAuthorityCount(pSid);

    // compute buffer length
    // S-SID_REVISION- + identifierauthority- + subauthorities- + NULL

    dwSidSize=(15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR);

    // allocate memory
 
	*TextualSid = (LPTSTR)malloc(dwSidSize);
	if(*TextualSid == NULL)
	{
		return false;
	}

    // Add 'S' prefix and revision number to the string.

    dwSidSize = wsprintf(*TextualSid, TEXT("S-%lu-"), dwSidRev);

    // Add SID identifier authority to the string.
 
    if ((psia->Value[0] != 0) || (psia->Value[1] != 0))
    {
        dwSidSize += wsprintf(*TextualSid + lstrlen(*TextualSid),
							  TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"),
							  (USHORT)psia->Value[0],
							  (USHORT)psia->Value[1],
							  (USHORT)psia->Value[2],
							  (USHORT)psia->Value[3],
							  (USHORT)psia->Value[4],
							  (USHORT)psia->Value[5]);
    }
    else
    {
        dwSidSize += wsprintf(*TextualSid + lstrlen(*TextualSid),
							  TEXT("%lu"),
							  (ULONG)(psia->Value[5]) +
							  (ULONG)(psia->Value[4] << 8) +
							  (ULONG)(psia->Value[3] << 16) +
							  (ULONG)(psia->Value[2] << 24));
    }

    // Loop through SidSubAuthorities and add them to the string.

    for (dwCounter=0; dwCounter<dwSubAuthorities; dwCounter++)
    {
        dwSidSize += wsprintf(*TextualSid + dwSidSize,
							  TEXT("-%lu"),
			                  *GetSidSubAuthority(pSid, dwCounter));
    }

    return true;
}
#endif

string Common::SwitchChar(string fixedString, string oldChr, string newChr)
{
	//------------------------------------------------------------------------------------//
	//  ABSTRACT
	//
	//  This function takes a string and searches for all oldChrs.  If one is found,
	//  it is replaced with a newChr.  It is only intended to work with a single char 
	//	at a time. No multiple char strings allowed
	//
	//------------------------------------------------------------------------------------//

	if(oldChr.length() != 1 || newChr.length() != 1)
		throw CommonException("Error: (SwitchChar) can only switch strings of length = 1.");

	unsigned int pos = fixedString.find(oldChr, 0);
	while (pos != string::npos)
	{
		fixedString.erase(pos, 1);
		fixedString.insert(pos, newChr);
		pos = fixedString.find(oldChr, pos+1);
	}

	return fixedString;
}

string Common::ToString(int num)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return a the int as a string
	//
	// -----------------------------------------------------------------------
	ostringstream result;
	result << num;

	return result.str();
}
string Common::ToString(long num)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return a the long as a string
	//
	// -----------------------------------------------------------------------
	ostringstream result;
	result << num;

	return result.str();
}
string Common::ToString(unsigned long num)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return a the unsigned long as a string
	//
	// -----------------------------------------------------------------------
	ostringstream result;
	result << num;

	return result.str();
}

//****************************************************************************************//
//							CommonException Class										  //	
//****************************************************************************************//
CommonException::CommonException() : Exception()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Default constructor simply set the severity to ERROR_FATAL. This is 
	//	done with the explicit call to the Exception class default constructor.
	//
	// -----------------------------------------------------------------------

}

CommonException::CommonException(string errMsgIn) : Exception(errMsgIn)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Set the error message and then set the severity to ERROR_FATAL. This is 
	//	done with the explicit call to the Exception class constructor that 
	//	takes a single string param.
	//
	// -----------------------------------------------------------------------

}

CommonException::~CommonException()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Do nothing for now
	//
	// -----------------------------------------------------------------------

}
