// Copyright (c) 1997-1999 Microsoft Corporation
#include "precomp.h"
#include "chklist.h"
#include "Principal.h"
#include "CHString1.h"

//-------------------------------------------------------------
CPrincipal::CPrincipal(CWbemClassObject &userInst, SecurityStyle secStyle) :
						m_secStyle(secStyle), 
						m_perms(0),
						m_inheritedPerms(0),
						m_editable(true)
{
	//------------------------------------------------
	// figure out what security strategy we're dealing with and load it
	// into my "generic" definition.

	memset(m_name, 0, 100 * sizeof(TCHAR));
	_tcsncpy(m_name, (LPCTSTR)userInst.GetString("Name"), 100);

	memset(m_domain, 0, 100 * sizeof(TCHAR));
	_tcsncpy(m_domain, (LPCTSTR)userInst.GetString("Authority"), 100);

	// if pre-M3 security...
	if(m_secStyle == RootSecStyle)
	{
		// this is the only instance for this guy so save it.

		// convert the convoluted "bits" into my real "generic" bits.
		m_perms |= (userInst.GetBool("EditSecurity") ? ACL_WRITE_DAC : 0);
		m_perms |= (userInst.GetBool("Enabled") ? ACL_ENABLE : 0);
		m_perms |= (userInst.GetBool("ExecuteMethods") ? ACL_METHOD_EXECUTE : 0);

		// NOTE: each "level" implies all the levels below so I INTENTIONALLY 
		// left out the 'breaks' so the bits would fall through and accumulate.
		switch(userInst.GetLong("Permissions"))
		{
		case 2:		// class write
			m_perms |= ACL_CLASS_WRITE;

		case 1:		// instance write
			m_perms |= ACL_INSTANCE_WRITE;
		}

		// remember for dirty bit processing later.
		m_origPerms = m_perms;
	}
	else  //new M3+ security
	{
		// ACL bits perfectly match m_perms.
		// NOTE: this securityStyle can have multiple aces per principal.
		AddAce(userInst);
	}
}

//------------------------------------------
// move m_perms into the checkboxes
void CPrincipal::LoadChecklist(HWND list, int OSType)
{
	INT_PTR itemCount = CBL_GetItemCount(list);
	CPermission *permItem = 0;
	UINT state;

	::EnableWindow(list, m_editable);

	// for each permission item...
	for(INT_PTR x = 0; x < itemCount; x++)
	{
		// which permission item is this
		permItem = (CPermission *)CBL_GetItemData(list, x);

		state = BST_UNCHECKED; // and enabled (local)

		// if its a local perm...
		if(IS_BITSET(m_perms, permItem->m_permBit))
		{
			// local perms override inherited perms.
			state = BST_CHECKED;
		}
		else if(IS_BITSET(m_inheritedPerms, permItem->m_permBit))
		{
			// you got it from your parent.
			state = CLST_CHECKDISABLED;
		}
		// set it.
		CBL_SetState(list, x, ALLOW_COL, state);
	} //endfor
}

//------------------------------------------
// move the checkboxes into m_perms.
void CPrincipal::SaveChecklist(HWND list, int OSType)
{
	INT_PTR itemCount = CBL_GetItemCount(list);
	CPermission *permItem = 0;
	LPARAM state = 0, state1 = 0;

	// clear this principal's perm bits.
	m_perms = 0;

	// for each perm...
	for(INT_PTR x = 0; x < itemCount; x++)
	{
		// get permission item.
		permItem = (CPermission *)CBL_GetItemData(list, x);

		// what's the check state?
		state = CBL_GetState(list, x, ALLOW_COL);

		// if its enabled (local) & checked, set the matching bit.
		// NOTE: This "explicit compare will eliminate CLST_DISABLEDed states which
		// shouldn't be saved off.
		if((state == BST_CHECKED) ||
		  ((state == CLST_CHECKDISABLED) && (OSType != OSTYPE_WINNT)))
		{
			m_perms |= permItem->m_permBit;
		}
	} //endfor
}

//------------------------------------------
// WARNING: this logic assumes it will only be called when the principal is
// being read in. If you want to add aces interactively, its a whole different
// game.
void CPrincipal::AddAce(CWbemClassObject &princ)
{
	DWORD flags = princ.GetLong("Flags");

	// if inherited...
	if(IS_BITSET(flags, INHERITED_ACE))
	{
		// simply accumulate bits.
		m_inheritedPerms |= princ.GetLong("Mask");
		m_editable = false;
	}
	else if(flags == CONTAINER_INHERIT_ACE)
	{
		m_perms |= princ.GetLong("Mask");

		// this is the first local ace, we can edit it so save the source instance.
		// NOTE: Any additional "local" aces that exactly match CONTAINER_INHERIT_ACE
		// will be merged in but the the ClassObject will be tossed.
		//if(!(bool)m_userInst)
		//{
	//		m_userInst = princ;
	//	}

		// remember for dirty bit processing later.
		m_origPerms = m_perms;
	}
	else
	{
		// this will disable the checklist control for this principal.
		m_editable = false;
	}
}

//------------------------------------------
HRESULT CPrincipal::DeleteSelf(CWbemServices &service)
{
	HRESULT hr = S_OK;

	if(m_secStyle == RootSecStyle)
	{
		CHString1 path, fmt("__NTLMuser.Name=\"%s\",Authority=\"%s\"");
		path.Format(fmt, m_name, m_domain);

		hr = service.DeleteInstance((LPCTSTR)path);
	}
	return hr;
}

//------------------------------------------
// move m_perms into the checkboxes
HRESULT CPrincipal::Put(CWbemServices &service, CWbemClassObject &userInst)
{
	HRESULT hr = E_FAIL;
	
	if(m_editable)
	{
		// if pre-M3 security...
		if(m_secStyle == RootSecStyle)
		{
			DWORD perm = 0;
			// convert my "generic" bits back to convoluted "bits".
			userInst = service.CreateInstance("__NTLMUser");
			userInst.Put("Name", (bstr_t)m_name);
			userInst.Put("Authority", (bstr_t)m_domain);
			userInst.Put("EditSecurity", (bool)((m_perms & ACL_WRITE_DAC) != 0));
			userInst.Put("Enabled", (bool)((m_perms & ACL_ENABLE) != 0));
			userInst.Put("ExecuteMethods", (bool)((m_perms & ACL_METHOD_EXECUTE) != 0));

			if(m_perms & ACL_CLASS_WRITE)
			{
				perm = 2;
			}
			else if(m_perms & ACL_INSTANCE_WRITE)
			{
				perm = 1;
			}
			else
			{
				perm = 0;
			}
			userInst.Put("Permissions", (long)perm);

			hr = service.PutInstance(userInst);
		}
		else  //new M3+ security
		{
			// ACL bits perfectly match m_perms.
			userInst = service.CreateInstance("__NTLMUser9x");
			userInst.Put("Name", (bstr_t)m_name);
			userInst.Put("Authority", (bstr_t)m_domain);
			userInst.Put("Flags", (long)CONTAINER_INHERIT_ACE);
			userInst.Put("Mask", (long)m_perms);
			userInst.Put("Type", (long)ACCESS_ALLOWED_ACE_TYPE);
			hr = S_OK;
		}
	}

	return hr;
}

//-----------------------------------------------------------------------------
// Indexes into the SID image list IDB_SID_ICONS.
#define IDB_GROUP                       0
#define IDB_USER                        1
#define IDB_ALIAS                       2
#define IDB_UNKNOWN                     3
#define IDB_SYSTEM                      4
#define IDB_REMOTE                      5
#define IDB_WORLD                       6
#define IDB_CREATOR_OWNER               7
#define IDB_NETWORK                     8
#define IDB_INTERACTIVE                 9
#define IDB_DELETEDACCOUNT              10

//TODO: match the magic strings when provider catches up.

int CPrincipal::GetImageIndex(void)
{
	UINT idBitmap = 0;
	return IDB_USER;
/*
	switch (m_SidType)
	{
	case SidTypeUser:
		return IDB_USER;
		break;

	case SidTypeGroup:
		return IDB_GROUP;
		break;

	case SidTypeAlias:
		return IDB_ALIAS;
		break;

	case SidTypeWellKnownGroup:
		if(_tcsicmp(m_name, _T("Everyone")) == 0)
		{
			return IDB_WORLD;
		}
		else if(_tcsicmp(m_name, _T("Creator Owner")) == 0)
		{
			return IDB_CREATOR_OWNER;
		}
		else if(_tcsicmp(m_name, _T("NETWORK")) == 0)
		{
			return IDB_NETWORK;
		}
		else if(_tcsicmp(m_name, _T("INTERACTIVE")) == 0)
		{
			return IDB_INTERACTIVE;
		}
		else if(_tcsicmp(m_name, _T("SYSTEM")) == 0)
		{
			return IDB_SYSTEM;
		}
		else
		{
			// wasn't that well known afterall  :)
			return IDB_GROUP;
		}
		break;

	case SidTypeDeletedAccount:
		return IDB_DELETEDACCOUNT;
		break;

	case SidTypeInvalid:
	case SidTypeUnknown:
		return IDB_UNKNOWN;
		break;

	case SidTypeDomain:
	default:
		// Should never get here.
		return IDB_UNKNOWN;
		break;
	}
	return IDB_UNKNOWN;
	*/
}