//
// $Id: Common.cpp,v 1.4 2004/07/08 15:24:24 bakerj Exp $
//
//************************** Property of the MITRE Corporation ***************************//
//
// Copyright (c) 2003 - The MITRE Corporation
//
// This file is part of the OVAL Definition Interpreter.
//
// The OVAL Definition 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 Definition 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
// Definition 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::dataFile			= "system-characteristics.xml";
string	Common::xmlfile				= "definitions.xml";
string	Common::outputFilename		= "results.xml";
string	Common::variablesFilename	= "variables.xml";
string	Common::xmlfileMD5			= "";
string	Common::startTime			= "";
bool	Common::generateMD5			= false;
bool	Common::outputToFile		= true;
bool	Common::saveData			= true;
bool	Common::useProvidedData		= false;
bool	Common::validateXMLSchemas	= true;
bool	Common::verifyXMLfile		= true;
bool	Common::useConfiguration	= true;
bool	Common::useVariableFile		= false;

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

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

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

string Common::GetXMLfile()
{
	return xmlfile;	
}

string Common::GetXMLfileMD5()
{
	return xmlfileMD5;	
}

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

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

bool Common::GetSaveData()
{
	return saveData;	
}

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

bool Common::GetUseProvidedData()
{
	return useProvidedData;	
}

bool Common::GetUseConfiguration()
{
	return useConfiguration;	
}

bool Common::GetUseVariableFile()
{
	return useVariableFile;	
}

bool Common::GetValidateXMLSchemas() 
{
	return validateXMLSchemas;
}

string Common::GetVariableFilename()
{
	return variablesFilename;	
}

bool Common::GetVerifyXMLfile()
{
	return verifyXMLfile;	
}

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

void Common::SetDataFile(string fileIn)
{
	dataFile = fileIn;	
}

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

void Common::SetXMLfile(string xmlfileIn)
{
	xmlfile = xmlfileIn;
}

void Common::SetXMLfileMD5(string xmlfileMD5In)
{
	xmlfileMD5 = xmlfileMD5In;
}

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

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

void Common::SetSaveData(bool saveIn)
{
	saveData = saveIn;
}

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

void Common::SetUseProvidedData(bool useDataIn)
{
	useProvidedData = useDataIn;
}

void Common::SetUseConfiguration(bool useConfigIn)
{
	useConfiguration = useConfigIn;
}

void Common::SetUseVariableFile(bool useVarsIn)
{
	useVariableFile = useVarsIn;
}

void Common::SetValidateXMLSchemas(bool validateXMLSchemasIn) 
{
	validateXMLSchemas = validateXMLSchemasIn;
}

void Common::SetVariableFilename(string varFilenameIn)
{
	variablesFilename = varFilenameIn;
}

void Common::SetVerifyXMLfile(bool verifyXMLfileIn)
{
	verifyXMLfile = verifyXMLfileIn;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  Public Members  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
#ifdef WIN32
bool Common::DisableAllPrivileges()
{
	//------------------------------------------------------------------------------------//
	//  ABSTRACT
	//
	//  This function disables all the privileges associated with the current process
	//  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,									// handle to the process
						(TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES),	// requested access types 
						&hAccessToken) == FALSE)					// new access token 
	{
		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::GetEnviromentVariable(string envVarIn)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Return the value of the environment variable specified. If it is not 
	//	found return NULL.
	//
	// -----------------------------------------------------------------------

	string value;
	value = getenv(envVarIn.c_str());

	//	Check the value 
	if(value.compare("") == 0)
	{
		string errMsg = "Message: Unable to find the value of: " + envVarIn + "\n";
		throw CommonException(errMsg);
	}

	return (value);
}

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::GetTimeStamp()
{
	//------------------------------------------------------------------------------------//
	//  ABSTRACT
	//
	//  Retrieve the date/time.  The final output will be in the format:
	//
	//    mm/dd/yyyy hh:mm:ss
	//
	//------------------------------------------------------------------------------------//

	char tmpbuf[128];
	
	time_t tmpTime;
	struct tm *todayTime;
	
	// Get the time as a long integer, then convert it to local time.
	time(&tmpTime);
	todayTime = localtime(&tmpTime);
	
	// Build the time string.
	char *format = "%Y%m%d%H%M%S";
	strftime(tmpbuf, 128-1, format, todayTime);

	// Make sure the buffer is null terminated.
	tmpbuf[sizeof(tmpbuf)-1] = '\0';
	
	return (tmpbuf);
}

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
	//
	// -----------------------------------------------------------------------

}
