//
// $Id: ActiveDirectoryData.cpp,v 1.13 2005/08/30 19:02:22 abuttner 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 "ActiveDirectoryData.h"

// Initialize the item Vector
sVector ActiveDirectoryData::items;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  Class ActiveDirectoryData  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//

ActiveDirectoryData::ActiveDirectoryData(DOMElement* testNodeIn)
{
	//------------------------------------------------------------------------------------//
	//
	//  ABSTRACT
	//
	//	Create an data object and set iits members based on the provided xml node
	//
	//------------------------------------------------------------------------------------//
	
	// Validate the test node.
	string testNodeName = XmlCommon::GetElementName((DOMElement*)testNodeIn);
	if (testNodeName.compare("activedirectory_test") != 0) {
		throw ProbeDataException("Error: (ActiveDirectoryData) Invalid test node specified.");
	}

	// Initialize the data members.
	naming_context = new ObjectElement();
	relative_dn = new ObjectElement();
	attribute = new ObjectElement();
	object_class = new DataElement();
	adstype = new DataElement();
	value = new DataElement();

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


	// Call the ParseNode() function to populate the new ActiveDirectoryData object that was
	// just initialized.
	ParseNode(testNodeIn);
}

ActiveDirectoryData::ActiveDirectoryData(nvpVector* dnVectorIn)
{
	//------------------------------------------------------------------------------------//
	//
	//  ABSTRACT
	//
	//	Create an empty data object
	//
	//------------------------------------------------------------------------------------//

	naming_context = new ObjectElement();
	relative_dn = new ObjectElement();
	attribute = new ObjectElement();
	object_class = new DataElement();
	adstype = new DataElement();
	value = new DataElement();

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

}

ActiveDirectoryData::~ActiveDirectoryData()
{
	//------------------------------------------------------------------------------------//
	//
	//  ABSTRACT
	//
	//	Delete data members
	//
	//------------------------------------------------------------------------------------//

	delete naming_context;
	delete relative_dn;
	delete attribute;
	delete object_class;
	delete adstype;
	delete value;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  Public Members  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//

void ActiveDirectoryData::Write()
{
	//------------------------------------------------------------------------------------//
	//
	//  ABSTRACT
	//
	//	Write a windows active directory data element to the data document.
	//
	//------------------------------------------------------------------------------------//

	// Create a string representation of the item
	string item = naming_context->object + ":" + relative_dn->object + ":" + attribute->object;

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

	// Create a new test node.
	DOMElement *activedirectoryItem = CreateNewItemNode(dataDocument, "activedirectory_item");

	// Add the object element
	DOMElement *objectElm = XmlCommon::AddChildElement(dataDocument, activedirectoryItem, "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 naming_context element.
	AddObjectChildElement(dataDocument, objectElm, "naming_context", this->naming_context);

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

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

	// Add the data section if the object status is exists
	if(objectStatus == exists && !this->isPatternMatchObject) {
		DOMElement *dataElm = XmlCommon::AddChildElement(dataDocument, activedirectoryItem, "data");

		AddDataChildElement(dataDocument, dataElm, "object_class", this->object_class);
		AddDataChildElement(dataDocument, dataElm, "adstype", this->adstype);
		AddDataChildElement(dataDocument, dataElm, "value", this->value);
	}

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  Private Members  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//

void ActiveDirectoryData::ParseNode(DOMElement* testNodeIn)
{
	//------------------------------------------------------------------------------------//
	//
	//  ABSTRACT
	//
	//	Parse the provided DOMNode, gathering all data to populate the current
	//  ActiveDirectoryData object.
	//	
	//------------------------------------------------------------------------------------//

	// Retreive the test id from the DOMNode.
	testId = XmlCommon::GetAttributeByName(testNodeIn, "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(testNodeIn, "object");
	if (object == NULL) {
		throw new ProbeDataException("Error: Unable to locate object section for test: " + testId + "\n");

	}

	// Loop over childern of the object node
	//	get a list of the child nodes and their values
	string childName	= "";
	string childValue	= "";
	string childOp		= "";

	DOMNodeList *objectChildren = object->getChildNodes();
	unsigned int index = 0;
	while(index < objectChildren->getLength())
	{
		DOMNode *tmpNode = objectChildren->item(index);


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

			childName = XmlCommon::GetElementName((DOMElement*)objectChild);
			childValue = XmlCommon::GetDataNodeValue(objectChild);
			childOp = XmlCommon::GetAttributeByName(objectChild, "operator");

			// Convert the type
			objectTypes curType;
			if(childOp.compare("pattern match") == 0) {
				curType = pattern_match;
				this->isPatternMatchObject = true;
			} else {
				curType = literal;
			}
			
			//	Get the naming_context value	
			if(childName.compare("naming_context")==0)
			{
				naming_context->object = childValue;
				naming_context->type = curType;
				
			//	Get the relative_dn value
			}else if(childName.compare("relative_dn")==0) {

				relative_dn->object = childValue;
				relative_dn->type = curType;
				
			//	Get the attribute value
			}else if(childName.compare("attribute")==0) {

				attribute->object = childValue;
				attribute->type = curType;

			}
		}

		index++;
	}
}
	