//
// $Id: FileData.cpp,v 1.17 2005/08/10 19:15:53 bakerj Exp $
//
//****************************************************************************************//
// Copyright (c) 2005, The MITRE Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice, this list
//       of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice, this 
//       list of conditions and the following disclaimer in the documentation and/or other
//       materials provided with the distribution.
//     * Neither the name of The MITRE Corporation nor the names of its contributors may be
//       used to endorse or promote products derived from this software without specific 
//       prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
// SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
// OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//****************************************************************************************//

#include "FileData.h"

//****************************************************************************************//
//								FilePermissionData Class								  //	
//****************************************************************************************//
// Initialize the item Vector
sVector FileData::items;

FileData::FileData(DOMElement *test)
{
  // -----------------------------------------------------------------------
  //	Abstract
  //
  //	Initialize a new FileData and populate with the node's data
  // -----------------------------------------------------------------------

	string testName = XmlCommon::GetElementName(test);
	if(testName.compare("permission_test") != 0 && testName.compare("file_test") != 0)
		throw ProbeDataException("Error: FileData() Invalid test node specified. Received: " + testName);


	//	Init the data members
	path = new ObjectElement();

	// attribute data
	type = new DataElement();
	group_id = new DataElement();
	user_id = new DataElement();
	a_time = new DataElement();
	c_time = new DataElement();
	m_time = new DataElement();
	md5 = new DataElement();
	size = new DataElement();

	// permission data
	gexec = new DataElement();
	gread = new DataElement();
	gwrite = new DataElement();
	oexec = new DataElement();
	oread = new DataElement();
	owrite = new DataElement();
	sgid = new DataElement();
	sticky = new DataElement();
	suid = new DataElement();
	uexec = new DataElement();
	uread = new DataElement();
	uwrite = new DataElement();

	// Call the parse node function
	ParseNode(test);
	
	// set the xmlns and schema location
	this->SetXmlnsAlias("unix");
	this->SetXmlns("http://oval.mitre.org/XMLSchema/system_characteristics#unix");
	this->SetSchemaLocation("http://oval.mitre.org/XMLSchema/system_characteristics#unix unix-system-characteristics-schema.xsd");
}

FileData::FileData()
{
  // -----------------------------------------------------------------------
  //	Abstract
  //
  //	Initialize a new FileData as an empty object.
  // -----------------------------------------------------------------------

	//	Init the data members
	path = new ObjectElement();

	// attribute data
	type = new DataElement();
	group_id = new DataElement();
	user_id = new DataElement();
	a_time = new DataElement();
	c_time = new DataElement();
	m_time = new DataElement();
	md5 = new DataElement();
	size = new DataElement();

	// permission data
	gexec = new DataElement();
	gread = new DataElement();
	gwrite = new DataElement();
	oexec = new DataElement();
	oread = new DataElement();
	owrite = new DataElement();
	sgid = new DataElement();
	sticky = new DataElement();
	suid = new DataElement();
	uexec = new DataElement();
	uread = new DataElement();
	uwrite = new DataElement();

	// set the xmlns and schema location
	this->SetXmlnsAlias("unix");
	this->SetXmlns("http://oval.mitre.org/XMLSchema/system_characteristics#unix");
	this->SetSchemaLocation("http://oval.mitre.org/XMLSchema/system_characteristics#unix unix-system-characteristics-schema.xsd");
}

FileData::~FileData()
{
  // -----------------------------------------------------------------------
  //	Abstract
  //
  //	Delete data memebers
  // -----------------------------------------------------------------------

	delete path;
	delete type;
	delete group_id;
	delete user_id;
	delete a_time;
	delete c_time;
	delete m_time;
	delete md5;
	delete size;
	delete gexec;
	delete gread;
	delete gwrite;
	delete oexec;
	delete oread;
	delete owrite;
	delete sgid;
	delete sticky;
	delete suid;
	delete uexec;
	delete uread;
	delete uwrite;
}

// ***************************************************************************************	//
//								Public members												//
// ***************************************************************************************	//
void FileData::Write()
{
  // -----------------------------------------------------------------------
  //	Abstract
  //
  //	Create a new permission_test node and add it to the dataDocument.
  //	
  // -----------------------------------------------------------------------

	// Create a string representation of the item
	string item = path->object;

	// Ensure that the item has not already been written
	if(WroteItem(&items, item))
		return;

	//	Create a new item node
	DOMElement *fileItem = CreateNewItemNode(dataDocument, "file_item");

	// Add the object element
	DOMElement *objectElm = XmlCommon::AddChildElement(dataDocument, fileItem, "object");

	// Add the status attribute to the object if not default value
	string strStatus = this->SwitchStatusType(this->objectStatus);
	if (strStatus.compare("exists") != 0)
		XmlCommon::AddAttribute(objectElm, "status", strStatus);

	//	Add the path element
	AddObjectChildElement(dataDocument, objectElm, "path", this->path);

	//    Only write permission bits if the path is found
	if (objectStatus == exists && !this->isPatternMatchObject) {
		DOMElement *dataElm = XmlCommon::AddChildElement(dataDocument, fileItem, "data");

		//	Add the type element
		AddDataChildElement(dataDocument, dataElm, "type", type);

		//	Add the group_id element
		AddDataChildElement(dataDocument, dataElm, "group_id", group_id);

		//	Add the user_id element
		AddDataChildElement(dataDocument, dataElm, "user_id", user_id);

		//	Add the a_time element
		AddDataChildElement(dataDocument, dataElm, "a_time", a_time);

		//	Add the c_time element
		AddDataChildElement(dataDocument, dataElm, "c_time", c_time);

		//	Add the m_time element
		AddDataChildElement(dataDocument, dataElm, "m_time", m_time);
		
		//	Add the md5 element
		AddDataChildElement(dataDocument, dataElm, "md5", md5);

		//	Add the size element
		AddDataChildElement(dataDocument, dataElm, "size", size);
	    
		//	Add the gexec element
		AddDataChildElement(dataDocument, dataElm, "gexec", gexec);
	  
		//	Add the gread element
		AddDataChildElement(dataDocument, dataElm, "gread", gread);

		//	Add the gwrite elemen
		AddDataChildElement(dataDocument, dataElm, "gwrite", gwrite);

		//	Add the oexec element
		AddDataChildElement(dataDocument, dataElm, "oexec", oexec);

		//	Add the oread element
		AddDataChildElement(dataDocument, dataElm, "oread", oread);

		//	Add the owrite element
		AddDataChildElement(dataDocument, dataElm, "owrite", owrite);

		//	Add the sgid element
		AddDataChildElement(dataDocument, dataElm, "sgid", sgid);

		//	Add the sticky element
		AddDataChildElement(dataDocument, dataElm, "sticky", sticky);

		//	Add the suid element
		AddDataChildElement(dataDocument, dataElm, "suid", suid);

		//	Add the uexec element
		AddDataChildElement(dataDocument, dataElm, "uexec", uexec);

		//	Add the uread element
		AddDataChildElement(dataDocument, dataElm, "uread", uread);

		//	Add the uwrite element
		AddDataChildElement(dataDocument, dataElm, "uwrite", uwrite);
    }

	// Add the new item to the data document
	InsertItem(dataDocument, fileItem, "file_items");
}

// ***************************************************************************************	//
//								Private members												//
// ***************************************************************************************	//
void FileData::ParseNode(DOMElement *test)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Parse a test node. Set all data elements for this FileData
	//	object.
	//	
	// -----------------------------------------------------------------------

	// Retreive the test id from the DOMNode.
	testId = XmlCommon::GetAttributeByName(test, "id");
	if (testId.compare("") == 0) {
		throw ProbeDataException("Error: Unable to find the 'id' attribute for specified the test.");
	}

	///////////////////////////////////////////////////////////////////////////
	//	Parse the node
	///////////////////////////////////////////////////////////////////////////
	// Get the object element
	DOMElement *object = XmlCommon::FindNodeNS(test, "object");
	if (object == NULL) {
		throw new ProbeDataException("Error: Unable to locate object section for test: " + testId + "\n");

	}

	// Get the path element - path is required
	DOMElement *pathNode = XmlCommon::FindNodeNS(object, "path");
	if (object == NULL) {
		throw new ProbeDataException("Error: Unable to locate path elemen for test: " + testId + "\n");

	}

	// get the operator for path
	string pathOperator = XmlCommon::GetAttributeByName(pathNode, "operator");
	if(pathOperator.compare("pattern match") == 0) {
		path->type = pattern_match;
		this->isPatternMatchObject = true;
	} else {
		path->type = literal;
	}


	// Get the components and their types
	string componentType	= "";
	string componentValue	= "";

	REGEX myMatcher;
	DOMNodeList *pathChildren = pathNode->getChildNodes();
	unsigned int index = 0;
	while(index < pathChildren->getLength())
	{
		DOMNode *tmpNode = pathChildren->item(index);

		//	only concerned with ELEMENT_NODEs
		if (tmpNode->getNodeType() == DOMNode::ELEMENT_NODE) {
			DOMElement* pathChild = (DOMElement*)tmpNode;

			componentValue = XmlCommon::GetDataNodeValue(pathChild);
			componentType = XmlCommon::GetAttributeByName(pathChild, "type");

			//	Build the file path
			path->object.append(componentValue);
		}
		index ++;
	}
}

