//
// $Id: GroupProbe.cpp,v 1.4 2007/01/09 17:43:02 bakerj Exp $
//
//****************************************************************************************//
// Copyright (c) 2002-2007, 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 "GroupProbe.h"

//****************************************************************************************//
//								GroupProbe Class											  //	
//****************************************************************************************//
GroupProbe* GroupProbe::instance = NULL;

GroupProbe::GroupProbe() : AbsProbe() {
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//
	// -----------------------------------------------------------------------
	
}

GroupProbe::~GroupProbe() {
	// -----------------------------------------------------------------------
	//
	//  ABSTRACT
	//
	//
	// -----------------------------------------------------------------------

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  Public Members  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
AbsProbe* GroupProbe::Instance() {
	// -----------------------------------------------------------------------
	//
	//  ABSTRACT
	//
	//	Ensure that the GroupProbe is a singleton.
	// -----------------------------------------------------------------------

	// Use lazy initialization
	if(instance == NULL) 
		instance = new GroupProbe();

	return instance;	
}

ItemVector* GroupProbe::CollectItems(Object *object) {
	// -----------------------------------------------------------------------
	//
	//  ABSTRACT
	//
	//  Run the group probe. Return a vector of Items
	//	Relies on the WindowsCommon class to searching for and enumerating
	//	Groups.
	// -----------------------------------------------------------------------
	
	ItemVector *collectedItems = new ItemVector();

	// get the trustee_name from the provided object
	ObjectEntity* group = object->GetElementByName("group");

	// check datatypes - only allow string
	if(group->GetDatatype() != OvalEnum::STRING_TYPE) {
		throw ProbeException("Error: invalid data type specified on group. Found: " + OvalEnum::DatatypeToString(group->GetDatatype()));
	}	

	// check operation - only allow  equals, not equals and pattern match
	if(group->GetOperation() != OvalEnum::EQUALS_OPERATION && group->GetOperation() != OvalEnum::PATTERN_MATCH_OPERATION && group->GetOperation() != OvalEnum::NOT_EQUAL_OPERATION) {
		throw ProbeException("Error: invalid operation specified on group. Found: " + OvalEnum::OperationToString(group->GetOperation()));
	}

	// behaviors are not allowed on groups

	if(object->GetBehaviors()->size() != 0) {
		throw ProbeException("Error group_objects do not support behaviors.");		
	}

	// get the group data
	if(group->GetVarRef() == NULL) {
		if(group->GetOperation() == OvalEnum::EQUALS_OPERATION) {
			// simply get the members of teh group if it exists
			Item* item=  this->GetGroupMembers(group->GetValue());
			if(item != NULL) {
				collectedItems->push_back(item);
			}
		} else {

			bool isRegex = false;
			if(group->GetOperation() == OvalEnum::PATTERN_MATCH_OPERATION)
				isRegex = true;

			// Get all groups on the system...
			StringVector* allGroups = WindowsCommon::GetAllGroups();
			
			// Get the set of groups that match the ItemEntity.
			StringVector::iterator iterator;
			for(iterator = allGroups->begin(); iterator != allGroups->end(); iterator++) {
				string curr = (*iterator);
				if(this->IsMatch(group->GetValue(), (*iterator), isRegex)) {
					Item* item =  this->GetGroupMembers((*iterator));
					if(item != NULL) {
						collectedItems->push_back(item);
					}
				}
			}
		}

	} else {
		// Get all groups on the system...
		StringVector* allGroups = WindowsCommon::GetAllGroups();

		// loop through all groups on the system
		// only keep those that match operation and value and var check
		StringVector::iterator it;
		ItemEntity* tmp = this->CreateItemEntity(group);
		for(it = allGroups->begin(); it != allGroups->end(); it++) {
			tmp->SetValue((*it));
			if(group->Analyze(tmp) == OvalEnum::TRUE_RESULT) {
				Item* item = this->GetGroupMembers((*it));
				if(item != NULL) {
					collectedItems->push_back(item);
				}
			}
		}
	}

	return collectedItems;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  Private Members  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
Item* GroupProbe::CreateItem() {
	// -----------------------------------------------------------------------
	//
	//  ABSTRACT
	//
	//  Return a new Item created for storing group information
	//
	// -----------------------------------------------------------------------

	Item* item = new Item(0, 
						"http://oval.mitre.org/XMLSchema/oval-system-characteristics-5#windows", 
						"win-sc", 
						"http://oval.mitre.org/XMLSchema/oval-system-characteristics-5#windows windows-system-characteristics-schema.xsd", 
						OvalEnum::ERROR_STATUS, 
						"group_item");

	return item;
}

Item* GroupProbe::GetGroupMembers(string groupName) {
	// -----------------------------------------------------------------------
	//
	//  ABSTRACT
	//
	//  Return a populated item if the group exists or NULL if not found.
	//	Throw any errors to the caller.
	//
	// -----------------------------------------------------------------------
	Item* item = NULL;

	StringVector* members = new StringVector();
	bool groupExists = WindowsCommon::ExpandGroup(groupName, members);

	if(groupExists) {
		item = this->CreateItem();
		item->SetStatus(OvalEnum::EXISTS_STATUS);
		item->AppendElement(new ItemEntity("group", groupName, OvalEnum::STRING_TYPE, true, OvalEnum::EXISTS_STATUS));

		StringVector::iterator iterator;
		if(members->size() > 0) {
			for(iterator = members->begin(); iterator != members->end(); iterator++) {
				item->AppendElement(new ItemEntity("user", (*iterator), OvalEnum::STRING_TYPE, false, OvalEnum::EXISTS_STATUS));
			}
		} else {
			item->AppendElement(new ItemEntity("user", "", OvalEnum::STRING_TYPE, false, OvalEnum::DOES_NOT_EXIST_STATUS));
		}
	}

	delete members;

	return item;
}
