//***************************************************************************
//
//  Copyright (c) 1998-2000 Microsoft Corporation
//
//  SECURITY.CPP
//
//  alanbos  28-Jun-98   Created.
//
//  Defines the implementation of CSWbemSecurity
//
//***************************************************************************

#include "precomp.h"

// Used to protect security calls
extern CRITICAL_SECTION g_csSecurity;

bool		CSWbemSecurity::s_bInitialized = false;
bool		CSWbemSecurity::s_bIsNT = false;
DWORD		CSWbemSecurity::s_dwNTMajorVersion = 0;
HINSTANCE	CSWbemSecurity::s_hAdvapi = NULL;
bool		CSWbemSecurity::s_bCanRevert = false;
WbemImpersonationLevelEnum	CSWbemSecurity::s_dwDefaultImpersonationLevel 
					= wbemImpersonationLevelIdentify;

// Declarations for function pointers that won't exist on Win9x
BOOL (STDAPICALLTYPE *s_pfnDuplicateTokenEx) (
	HANDLE, 
	DWORD, 
	LPSECURITY_ATTRIBUTES,
	SECURITY_IMPERSONATION_LEVEL, 
	TOKEN_TYPE,
	PHANDLE
) = NULL; 

//***************************************************************************
//
//  SCODE CSWbemSecurity::Initialize
//
//  DESCRIPTION:
//
//  This static function is caused on DLL attachment to the process; it
//	sets up the function pointers for advanced API privilege functions.
//	On Win9x these functions are not supported which is why we need to
//	indirect through GetProcAddress.
//
//***************************************************************************
 
void CSWbemSecurity::Initialize ()
{
	EnterCriticalSection (&g_csSecurity);

	if (!s_bInitialized)
	{
		// Get OS info
		OSVERSIONINFO	osVersionInfo;
		osVersionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);

		GetVersionEx (&osVersionInfo);
		s_bIsNT = (VER_PLATFORM_WIN32_NT == osVersionInfo.dwPlatformId);
		s_dwNTMajorVersion = osVersionInfo.dwMajorVersion;

		if (s_bIsNT)
		{
			HKEY hKey;

			// Security values are relevant for NT only - for Win9x leave as default
			if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
					WBEMS_RK_SCRIPTING, 0, KEY_QUERY_VALUE, &hKey))
			{
				DWORD dwDummy = 0;

				// Get revert flag value from registry - NT 4.0 or less only
				if (s_dwNTMajorVersion <= 4)
				{
					DWORD dwEnableForAsp = 0;
					dwDummy = sizeof (dwEnableForAsp);
				
					if (ERROR_SUCCESS == RegQueryValueEx (hKey, WBEMS_RV_ENABLEFORASP, 
							NULL, NULL, (BYTE *) &dwEnableForAsp,  &dwDummy))
						s_bCanRevert = (0 != dwEnableForAsp);
				}

				// Get default impersonation level from registry
				DWORD dwImpLevel = 0;
				dwDummy = sizeof (dwImpLevel);
			
				if (ERROR_SUCCESS == RegQueryValueEx (hKey, WBEMS_RV_DEFAULTIMPLEVEL, 
							NULL, NULL, (BYTE *) &dwImpLevel,  &dwDummy))
					s_dwDefaultImpersonationLevel = (WbemImpersonationLevelEnum) dwImpLevel;

				RegCloseKey (hKey);
			}

			// Set up security function pointers for NT
			if (!s_hAdvapi)
			{
				TCHAR	dllName [] = _T("\\advapi32.dll");
				LPTSTR  pszSysDir = new TCHAR[ MAX_PATH + _tcslen (dllName) + 1];

				if (pszSysDir)
				{
					pszSysDir[0] = NULL;
					UINT    uSize = GetSystemDirectory(pszSysDir, MAX_PATH);
					
					if(uSize > MAX_PATH) {
						delete[] pszSysDir;
						pszSysDir = new TCHAR[ uSize + _tcslen (dllName) + 1];
        				
						if (pszSysDir)
						{
							pszSysDir[0] = NULL;
							uSize = GetSystemDirectory(pszSysDir, uSize);
						}
					}

					if (pszSysDir)
					{
						_tcscat (pszSysDir, dllName);
						s_hAdvapi = LoadLibraryEx (pszSysDir, NULL, 0);
						
						if (s_hAdvapi)
							(FARPROC&) s_pfnDuplicateTokenEx = GetProcAddress(s_hAdvapi, "DuplicateTokenEx");

						delete [] pszSysDir;
					}
				}
			}
		}

		s_bInitialized = true;
	}
	
	LeaveCriticalSection (&g_csSecurity);
}

//***************************************************************************
//
//  SCODE CSWbemSecurity::Uninitialize
//
//  DESCRIPTION:
//
//  This static function is caused on DLL detachment to the process; it
//	unloads the API loaded by Initialize (above) to obtain function pointers.
//
//***************************************************************************

void CSWbemSecurity::Uninitialize ()
{
	EnterCriticalSection (&g_csSecurity);
	
	if (s_hAdvapi)
	{
		s_pfnDuplicateTokenEx = NULL;
		FreeLibrary (s_hAdvapi);
		s_hAdvapi = NULL;
	}

	LeaveCriticalSection (&g_csSecurity);
}


//***************************************************************************
//
//  SCODE CSWbemSecurity::LookupPrivilegeValue
//
//  DESCRIPTION:
//
//  This static function wraps the Win32 LookupPrivilegeValue function,
//	allowing us to do some OS-dependent stuff.
//
//  PARAMETERS:
//
//		lpName		the privilege name
//		lpLuid		holds the LUID on successful return
//
//  RETURN VALUES:
//
//		true		On NT this means we found the privilege. On Win9x we
//					always return this.
//
//		false		On NT this means the privilege is not recognized.  This
//					is never returned on Win9x.
//
//***************************************************************************
 
BOOL CSWbemSecurity::LookupPrivilegeValue (
	LPCTSTR lpName, 
	PLUID lpLuid
)
{
	// Allows any name to map to 0 LUID on Win9x - this aids script portability
	if (IsNT ())
		return ::LookupPrivilegeValue(NULL, lpName, lpLuid);
	else
		return true;
}

//***************************************************************************
//
//  SCODE CSWbemSecurity::LookupPrivilegeDisplayName
//
//  DESCRIPTION:
//
//  This static function wraps the Win32 LookupPrivilegeDisplayName function,
//	allowing us to do some OS-dependent stuff.
//
//  PARAMETERS:
//
//		tName			the privilege name
//		pDisplayName	holds the display name on successful return
//
//***************************************************************************

void CSWbemSecurity::LookupPrivilegeDisplayName (LPCTSTR lpName, BSTR *pDisplayName)
{
	if (pDisplayName)
	{
		// Can't return display name on Win9x (no privilege support)
		if (IsNT ())
		{
			DWORD dwLangID;
			DWORD dwSize = 1;
			TCHAR dummy [1];
					
			// Get size of required buffer
			::LookupPrivilegeDisplayName (NULL, lpName, dummy, &dwSize, &dwLangID);
			LPTSTR dname = new TCHAR[dwSize + 1];

			if (dname)
			{
				if (::LookupPrivilegeDisplayName (_T(""), lpName, dname, &dwSize, &dwLangID))
				{
					// Have a valid name - now copy it to a BSTR
#ifdef _UNICODE 
					*pDisplayName = SysAllocString (dname);
#else
					size_t dnameLen = strlen (dname);
					OLECHAR *nameW = new OLECHAR [dnameLen + 1];

					if (nameW)
					{
						mbstowcs (nameW, dname, dnameLen);
						nameW [dnameLen] = NULL;
						*pDisplayName = SysAllocString (nameW);
						delete [] nameW;
					}
#endif
				}

				delete [] dname;
			}
		}

		// If we failed, just set an empty string
		if (!(*pDisplayName))
			*pDisplayName = SysAllocString (L"");
	}
}

//***************************************************************************
//
// CSWbemSecurity::CSWbemSecurity
//
// CONSTRUCTOR
//		This form of the constructor is used for securing a new WBEM 
//		remoted interface where no previous security has been applied.  
//		It is only used to secure IWbemServices interfaces.
//		Note that the Locator may have security settings so these are
//		transferred if present.
//
//***************************************************************************

CSWbemSecurity::CSWbemSecurity (
	IUnknown *pUnk,
	BSTR bsAuthority ,
	BSTR bsUser, 
	BSTR bsPassword,
	CWbemLocatorSecurity *pLocatorSecurity) :
		m_pPrivilegeSet (NULL),
		m_pProxyCache (NULL),
		m_pCurProxy (NULL)
{
	m_Dispatch.SetObj (this, IID_ISWbemSecurity, 
				CLSID_SWbemSecurity, L"SWbemSecurity");
	m_cRef=1;
		
	m_pProxyCache = new CSWbemProxyCache (pUnk, bsAuthority,
							bsUser, bsPassword, pLocatorSecurity);

	if (m_pProxyCache)
		m_pCurProxy = m_pProxyCache->GetInitialProxy ();

	if (pLocatorSecurity)
	{
		// Clone the privilege set

		CSWbemPrivilegeSet *pPrivilegeSet = pLocatorSecurity->GetPrivilegeSet ();

		if (pPrivilegeSet)
		{
			m_pPrivilegeSet = new CSWbemPrivilegeSet (*pPrivilegeSet);
			pPrivilegeSet->Release ();
		}
	}
	else
	{
		// Create a new privilege set
	
		m_pPrivilegeSet = new CSWbemPrivilegeSet;
	}

	InterlockedIncrement(&g_cObj);
}

//***************************************************************************
//
// CSWbemSecurity::CSWbemSecurity
//
// CONSTRUCTOR
//		This form of the constructor is used for securing a new WBEM 
//		remoted interface where no previous security has been applied,
//		and where the user credentials are expressed in the form of an
//		encrypted COAUTHIDENTITY plus principal and authority.  
//		It is only used to secure IWbemServices interfaces.
//
//***************************************************************************

CSWbemSecurity::CSWbemSecurity (
	IUnknown *pUnk,
	COAUTHIDENTITY *pCoAuthIdentity,
	BSTR bsPrincipal,
	BSTR bsAuthority) :
		m_pPrivilegeSet (NULL),
		m_pProxyCache (NULL),
		m_pCurProxy (NULL)
{
	m_Dispatch.SetObj (this, IID_ISWbemSecurity, 
					CLSID_SWbemSecurity, L"SWbemSecurity");
	m_cRef=1;
		
	m_pProxyCache = new CSWbemProxyCache (pUnk, pCoAuthIdentity,
							bsPrincipal, bsAuthority);

	if (m_pProxyCache)
		m_pCurProxy = m_pProxyCache->GetInitialProxy ();

	// Create a new privilege set
	m_pPrivilegeSet = new CSWbemPrivilegeSet;

	InterlockedIncrement(&g_cObj);
}
//***************************************************************************
//
// CSWbemSecurity::CSWbemSecurity
//
// CONSTRUCTOR
//		This form of the constructor is used for securing a new WBEM interface
//		non-remoted interface using the security attributes attached to another 
//		(already secured) remoted interface; a non-remoted interface is secured
//		by virtue of securing a new proxy on an underlying remoted interface.  
//		It is used to "secure" an ISWbemObjectEx interface using the security 
//		settings of an IWbemServices interface.
//
//***************************************************************************

CSWbemSecurity::CSWbemSecurity (
	CSWbemSecurity *pSecurity) :
		m_pPrivilegeSet (NULL),
		m_pProxyCache (NULL),
		m_pCurProxy (NULL)
{
	m_Dispatch.SetObj (this, IID_ISWbemSecurity, 
					CLSID_SWbemSecurity, L"SWbemSecurity");
	m_cRef=1;

	// Clone the privilege set
	if (pSecurity)
	{
		CSWbemPrivilegeSet *pPrivilegeSet = pSecurity->GetPrivilegeSet ();

		if (pPrivilegeSet)
		{
			m_pPrivilegeSet = new CSWbemPrivilegeSet (*pPrivilegeSet);
			pPrivilegeSet->Release ();
		}
		else
		{
			// Create a new one
			m_pPrivilegeSet = new CSWbemPrivilegeSet ();
		}

		m_pProxyCache = pSecurity->GetProxyCache ();
		m_pCurProxy = pSecurity->GetProxy ();
	}

	InterlockedIncrement(&g_cObj);
}

CSWbemSecurity::CSWbemSecurity (
	IUnknown *pUnk,
	ISWbemInternalSecurity *pISWbemInternalSecurity) :
		m_pPrivilegeSet (NULL),
		m_pProxyCache (NULL),
		m_pCurProxy (NULL)
{
	m_Dispatch.SetObj (this, IID_ISWbemSecurity, 
					CLSID_SWbemSecurity, L"SWbemSecurity");
	m_cRef=1;

	if (pISWbemInternalSecurity)
	{
		// Clone the privilege set
		ISWbemSecurity *pISWbemSecurity = NULL;

		if (SUCCEEDED(pISWbemInternalSecurity->QueryInterface (IID_ISWbemSecurity,
							(void**) &pISWbemSecurity)))
		{
			ISWbemPrivilegeSet *pISWbemPrivilegeSet = NULL;

			if (SUCCEEDED(pISWbemSecurity->get_Privileges (&pISWbemPrivilegeSet)))
			{
				// Build the privilege set
				m_pPrivilegeSet = new CSWbemPrivilegeSet (pISWbemPrivilegeSet);

				// Build the proxy cache
				BSTR bsAuthority = NULL;
				BSTR bsPrincipal = NULL;
				BSTR bsUser = NULL;
				BSTR bsPassword = NULL;
				BSTR bsDomain = NULL;
				
				pISWbemInternalSecurity->GetAuthority (&bsAuthority);
				pISWbemInternalSecurity->GetPrincipal (&bsPrincipal);
				pISWbemInternalSecurity->GetUPD (&bsUser, &bsPassword, &bsDomain);
				
				COAUTHIDENTITY *pCoAuthIdentity = NULL;

				// Decide if we need a COAUTHIDENTITY
				if ((bsUser && (0 < wcslen (bsUser))) ||
					(bsPassword && (0 < wcslen (bsPassword))) ||
					(bsDomain && (0 < wcslen (bsDomain))))
					WbemAllocAuthIdentity (bsUser, bsPassword, bsDomain, &pCoAuthIdentity);

				m_pProxyCache = new CSWbemProxyCache (pUnk, pCoAuthIdentity,
									bsPrincipal, bsAuthority);

				if (pCoAuthIdentity)
					WbemFreeAuthIdentity (pCoAuthIdentity);

				if (bsAuthority)
					SysFreeString (bsAuthority);

				if (bsPrincipal)
					SysFreeString (bsPrincipal);

				if (bsUser)
					SysFreeString (bsUser);

				if (bsPassword)
					SysFreeString (bsPassword);

				if (bsDomain)
					SysFreeString (bsDomain);

				if (m_pProxyCache)
					m_pCurProxy = m_pProxyCache->GetInitialProxy ();
			}

			pISWbemPrivilegeSet->Release ();
		}

		pISWbemSecurity->Release ();
	}

	InterlockedIncrement(&g_cObj);
}

//***************************************************************************
//
// CSWbemSecurity::CSWbemSecurity
//
// CONSTRUCTOR
//		This form of the constructor is used for securing a new WBEM remoted
//		interface interface using the security attributes attached to another 
//		(already secured) remoted interface.
//		It is used to "secure" an ISWbemObjectSet interface using the security 
//		settings of an IWbemServices interface.
//
//***************************************************************************

CSWbemSecurity::CSWbemSecurity (
	IUnknown *pUnk,
	CSWbemSecurity *pSecurity) :
		m_pPrivilegeSet (NULL),
		m_pProxyCache (NULL),
		m_pCurProxy (NULL)
{
	m_Dispatch.SetObj (this, IID_ISWbemSecurity, 
						CLSID_SWbemSecurity, L"SWbemSecurity");
	m_cRef=1;
	InterlockedIncrement(&g_cObj);

	if (pSecurity)
	{
		// Clone the privilege set
		CSWbemPrivilegeSet *pPrivilegeSet = pSecurity->GetPrivilegeSet ();

		if (pPrivilegeSet)
		{
			m_pPrivilegeSet = new CSWbemPrivilegeSet (*pPrivilegeSet);
			pPrivilegeSet->Release ();
		}
		
		m_pProxyCache = new CSWbemProxyCache (pUnk, pSecurity);

		if (m_pProxyCache)
			m_pCurProxy = m_pProxyCache->GetInitialProxy ();
	}
	else
	{
		m_pPrivilegeSet = new CSWbemPrivilegeSet ();
		m_pProxyCache = new CSWbemProxyCache (pUnk, NULL);

		if (m_pProxyCache)
			m_pCurProxy = m_pProxyCache->GetInitialProxy ();
	}
}

//***************************************************************************
//
// CSWbemSecurity::~CSWbemSecurity
//
// DESTRUCTOR
//
//***************************************************************************

CSWbemSecurity::~CSWbemSecurity (void)
{
	InterlockedDecrement(&g_cObj);

	if (m_pCurProxy)
		m_pCurProxy->Release ();

	if (m_pProxyCache)
		m_pProxyCache->Release ();

	if (m_pPrivilegeSet)
		m_pPrivilegeSet->Release ();
}

//***************************************************************************
// HRESULT CSWbemSecurity::QueryInterface
// long CSWbemSecurity::AddRef
// long CSWbemSecurity::Release
//
// DESCRIPTION:
//
// Standard Com IUNKNOWN functions.
//
//***************************************************************************

STDMETHODIMP CSWbemSecurity::QueryInterface (

	IN REFIID riid,
    OUT LPVOID *ppv
)
{
    *ppv=NULL;

    if (IID_IUnknown==riid)
		*ppv = reinterpret_cast<IUnknown*>(this);
	else if (IID_ISWbemSecurity==riid)
		*ppv = (ISWbemSecurity *)this;
	else if (IID_IDispatch==riid)
        *ppv = (IDispatch *)this;
	else if (IID_ISupportErrorInfo==riid)
		*ppv = (ISupportErrorInfo *)this;
	else if (IID_ISWbemInternalSecurity==riid)
		*ppv = (ISWbemInternalSecurity *)this;
	else if (IID_IProvideClassInfo==riid)
		*ppv = (IProvideClassInfo *)this;

    if (NULL!=*ppv)
    {
        ((LPUNKNOWN)*ppv)->AddRef();
        return NOERROR;
    }

    return ResultFromScode(E_NOINTERFACE);
}

STDMETHODIMP_(ULONG) CSWbemSecurity::AddRef(void)
{
    long l = InterlockedIncrement(&m_cRef);
    return l;
}

STDMETHODIMP_(ULONG) CSWbemSecurity::Release(void)
{
    long l = InterlockedDecrement(&m_cRef);
    if (0L!=l)
        return l;
    delete this;
    return 0;
}

//***************************************************************************
// HRESULT CSWbemSecurity::InterfaceSupportsErrorInfo
//
// DESCRIPTION:
//
// Standard Com ISupportErrorInfo functions.
//
//***************************************************************************

STDMETHODIMP CSWbemSecurity::InterfaceSupportsErrorInfo (IN REFIID riid)
{
	return (IID_ISWbemSecurity == riid) ? S_OK : S_FALSE;
}

//***************************************************************************
//
//  SCODE CSWbemSecurity::get_AuthenticationLevel
//
//  DESCRIPTION:
//
//  Retrieve the authentication level
//
//  PARAMETERS:
//
//		pAuthenticationLevel		holds the value on return
//
//  RETURN VALUES:
//
//  WBEM_S_NO_ERROR				success
//	WBEM_E_INVALID_PARAMETER	bad input parameters
//  WBEM_E_FAILED				otherwise
//
//***************************************************************************

HRESULT CSWbemSecurity::get_AuthenticationLevel (
	WbemAuthenticationLevelEnum *pAuthenticationLevel
)
{
	HRESULT hr = WBEM_E_FAILED;

	ResetLastErrors ();

	if (NULL == pAuthenticationLevel)
		hr = WBEM_E_INVALID_PARAMETER;
	else if (m_pCurProxy)
	{
		DWORD dwAuthnLevel;
		DWORD dwImpLevel;

		if (S_OK == GetAuthImp (m_pCurProxy, &dwAuthnLevel, &dwImpLevel))
		{
			*pAuthenticationLevel = (WbemAuthenticationLevelEnum) dwAuthnLevel;
			hr = WBEM_S_NO_ERROR;
		}
	}

	if (FAILED(hr))
		m_Dispatch.RaiseException (hr);

	return hr;
}

//***************************************************************************
//
//  SCODE CSWbemSecurity::put_AuthenticationLevel
//
//  DESCRIPTION:
//
//  Set the authentication level
//
//  PARAMETERS:
//
//		authenticationLevel		the new value
//
//  RETURN VALUES:
//
//  WBEM_S_NO_ERROR				success
//	WBEM_E_INVALID_PARAMETER	bad input parameters
//  WBEM_E_FAILED				otherwise
//
//***************************************************************************

HRESULT CSWbemSecurity::put_AuthenticationLevel (
	WbemAuthenticationLevelEnum authenticationLevel
)
{
	HRESULT hr = WBEM_E_FAILED;

	ResetLastErrors ();

	if ((WBEMS_MIN_AUTHN_LEVEL > authenticationLevel) || 
		(WBEMS_MAX_AUTHN_LEVEL < authenticationLevel))
		hr = WBEM_E_INVALID_PARAMETER;
	else if (m_pCurProxy && m_pProxyCache)
	{
		DWORD dwAuthnLevel;
		DWORD dwImpLevel;

		if (S_OK == GetAuthImp (m_pCurProxy, &dwAuthnLevel, &dwImpLevel))
		{
			// Only refressh from cache if settings have changed
			if (authenticationLevel != (WbemAuthenticationLevelEnum) dwAuthnLevel)
			{
				m_pCurProxy->Release ();
				m_pCurProxy = NULL;

				m_pCurProxy = m_pProxyCache->GetProxy 
								(authenticationLevel, (WbemImpersonationLevelEnum) dwImpLevel);
			}
			
			hr = WBEM_S_NO_ERROR;
		}
	}
 	
	if (FAILED(hr))
		m_Dispatch.RaiseException (hr);

	return hr;
}

//***************************************************************************
//
//  SCODE CSWbemSecurity::get_ImpersonationLevel
//
//  DESCRIPTION:
//
//  Retrieve the impersonation level
//
//  PARAMETERS:
//
//		pImpersonationLevel		holds the value on return
//
//  RETURN VALUES:
//
//  WBEM_S_NO_ERROR				success
//	WBEM_E_INVALID_PARAMETER	bad input parameters
//  WBEM_E_FAILED				otherwise
//
//***************************************************************************

HRESULT CSWbemSecurity::get_ImpersonationLevel (
	WbemImpersonationLevelEnum *pImpersonationLevel
)
{
	HRESULT hr = WBEM_E_FAILED;

	ResetLastErrors ();

	if (NULL == pImpersonationLevel)
		hr = WBEM_E_INVALID_PARAMETER;
	else if (m_pCurProxy)
	{
		DWORD dwAuthnLevel;
		DWORD dwImpLevel;

		if (S_OK == GetAuthImp (m_pCurProxy, &dwAuthnLevel, &dwImpLevel))
		{
			*pImpersonationLevel = (WbemImpersonationLevelEnum) dwImpLevel;
			hr = WBEM_S_NO_ERROR;
		}
	}
	
	if (FAILED(hr))
		m_Dispatch.RaiseException (hr);

	return hr;
}

//***************************************************************************
//
//  SCODE CSWbemSecurity::put_ImpersonationLevel
//
//  DESCRIPTION:
//
//  Set the impersonation level
//
//  PARAMETERS:
//
//		impersonationLevel		the new value
//
//  RETURN VALUES:
//
//  WBEM_S_NO_ERROR				success
//	WBEM_E_INVALID_PARAMETER	bad input parameters
//  WBEM_E_FAILED				otherwise
//
//***************************************************************************

HRESULT CSWbemSecurity::put_ImpersonationLevel (
	WbemImpersonationLevelEnum impersonationLevel
)
{
	HRESULT hr = WBEM_E_FAILED;

	ResetLastErrors ();

	if ((WBEMS_MIN_IMP_LEVEL > impersonationLevel) || (WBEMS_MAX_IMP_LEVEL < impersonationLevel))
		hr = WBEM_E_INVALID_PARAMETER;
	else if (m_pCurProxy && m_pProxyCache)
	{
		DWORD dwAuthnLevel;
		DWORD dwImpLevel;

		if (S_OK == GetAuthImp (m_pCurProxy, &dwAuthnLevel, &dwImpLevel))
		{
			// Only refressh from cache if settings have changed
			if (impersonationLevel != (WbemImpersonationLevelEnum) dwImpLevel)
			{
				m_pCurProxy->Release ();
				m_pCurProxy = NULL;

				m_pCurProxy = m_pProxyCache->GetProxy 
							((WbemAuthenticationLevelEnum) dwAuthnLevel, impersonationLevel);
			}
			
			hr = WBEM_S_NO_ERROR;
		}
	}
 	 		
	if (FAILED(hr))
		m_Dispatch.RaiseException (hr);

	return hr;
}

//***************************************************************************
//
//  SCODE CSWbemSecurity::get_Privileges
//
//  DESCRIPTION:
//
//  Return the Privilege override set
//
//  WBEM_S_NO_ERROR				success
//	WBEM_E_INVALID_PARAMETER	bad input parameters
//  WBEM_E_FAILED				otherwise
//
//***************************************************************************

HRESULT CSWbemSecurity::get_Privileges	(
	ISWbemPrivilegeSet **ppPrivileges
)
{
	HRESULT hr = WBEM_E_FAILED;

	ResetLastErrors ();

	if (NULL == ppPrivileges)
		hr = WBEM_E_INVALID_PARAMETER;
	{
		*ppPrivileges = NULL;

		if (m_pPrivilegeSet)
		{
			if (SUCCEEDED (m_pPrivilegeSet->QueryInterface (IID_ISWbemPrivilegeSet,
												(PPVOID) ppPrivileges)))
				hr = WBEM_S_NO_ERROR;
		}
	}
	
	if (FAILED(hr))
		m_Dispatch.RaiseException (hr);
			
	return hr;
}

//***************************************************************************
//
//  CSWbemSecurity::SecureInterface
//
//  DESCRIPTION:
//
//  Set the security on the specified interface using the security settings
//	on this interface.
//
//  PARAMETERS:
//
//		pUnk		The interface to secure
//
//  RETURN VALUES:
//		none
//***************************************************************************

void CSWbemSecurity::SecureInterface (IUnknown *pUnk)
{
	if(pUnk)
	{
		if (m_pCurProxy)
		{
			DWORD dwAuthnLevel;
			DWORD dwImpLevel;

			if (S_OK == GetAuthImp (m_pCurProxy, &dwAuthnLevel, &dwImpLevel))
				if (m_pProxyCache)
					m_pProxyCache->SecureProxy (pUnk, 
							(WbemAuthenticationLevelEnum) dwAuthnLevel, 
							(WbemImpersonationLevelEnum) dwImpLevel);
		}
	}
}


//***************************************************************************
//
//  CSWbemSecurity::SecureInterfaceRev
//
//  DESCRIPTION:
//
//  Set the security on this interface using the security settings
//	on the specified interface.
//
//  PARAMETERS:
//
//		pUnk		The interface whose security settings we will 
//					use to set this interface
//
//  RETURN VALUES:
//		none
//***************************************************************************

void CSWbemSecurity::SecureInterfaceRev (IUnknown *pUnk)
{
	if (pUnk)
	{
		DWORD dwAuthnLevel;
		DWORD dwImpLevel;

		if (S_OK == GetAuthImp (pUnk, &dwAuthnLevel, &dwImpLevel))
		{
			if (m_pCurProxy)
			{
				m_pCurProxy->Release ();
				m_pCurProxy = NULL;
			}

			if (m_pProxyCache)
			{
				m_pCurProxy = m_pProxyCache->GetProxy 
						((WbemAuthenticationLevelEnum) dwAuthnLevel, 
						 (WbemImpersonationLevelEnum) dwImpLevel);
			}
		}
	}
}

//***************************************************************************
//
//  CSWbemSecurity::AdjustTokenPrivileges
//
//  DESCRIPTION:
//
//  Adjust the Privileges on the specified token without allowing a future
//	restore of the current settings..
//
//  PARAMETERS:
//
//		hHandle			Handle of the token on which to adjust privileges
//		pPrivilegeSet	Specified privilege adjustments
//
//  RETURN VALUES:
//		none
//***************************************************************************

void CSWbemSecurity::AdjustTokenPrivileges (
	HANDLE hHandle, 
	CSWbemPrivilegeSet *pPrivilegeSet
)
{
	DWORD lastErr = 0;

	if (pPrivilegeSet)
	{
		pPrivilegeSet->AddRef ();

		long lNumPrivileges = 0;
		pPrivilegeSet->get_Count (&lNumPrivileges);

		if (lNumPrivileges)
		{
			DWORD dwPrivilegeIndex = 0;

			/*
			 * Set up the token privileges array. Note that some jiggery-pokery
			 * is required here because the Privileges field is an [ANYSIZE_ARRAY]
			 * type.
			 */
			TOKEN_PRIVILEGES *pTokenPrivileges = (TOKEN_PRIVILEGES *) 
						new BYTE [sizeof(TOKEN_PRIVILEGES) + (lNumPrivileges * sizeof (LUID_AND_ATTRIBUTES [1]))];

			if (pTokenPrivileges)
			{
				// Get the iterator
				PrivilegeMap::iterator next = pPrivilegeSet->m_PrivilegeMap.begin ();

				while (next != pPrivilegeSet->m_PrivilegeMap.end ())
				{
					CSWbemPrivilege *pPrivilege = (*next).second;
					pPrivilege->AddRef ();
					LUID luid;
					pPrivilege->GetLUID (&luid);
					VARIANT_BOOL vBool;
					pPrivilege->get_IsEnabled (&vBool);

					pTokenPrivileges->Privileges [dwPrivilegeIndex].Luid = luid;

					/*
					 * Note that any setting other than SE_PRIVILEGE_ENABLED
					 * is interpreted by AdjustTokenPrivileges as a DISABLE
					 * request for that Privilege.
					 */
					pTokenPrivileges->Privileges [dwPrivilegeIndex].Attributes
						= (VARIANT_TRUE == vBool) ?
						SE_PRIVILEGE_ENABLED : SE_PRIVILEGE_ENABLED_BY_DEFAULT;

					dwPrivilegeIndex++;
					pPrivilege->Release ();
					next++;
				}

				// Now we should have recorded the number of privileges that were OK

				if (0 < dwPrivilegeIndex)
				{
					pTokenPrivileges->PrivilegeCount = dwPrivilegeIndex;

					BOOL result = ::AdjustTokenPrivileges (hHandle, FALSE, pTokenPrivileges, 0, NULL, NULL);
					lastErr = GetLastError ();
				}

				delete [] pTokenPrivileges;
			}
		}

		pPrivilegeSet->Release ();
	}
}

//***************************************************************************
//
//  SCODE CSWbemSecurity::SetSecurity
//
//  DESCRIPTION:
//
//  Set Privileges on the Thread Token.
//
//***************************************************************************

BOOL CSWbemSecurity::SetSecurity (
	bool &needToResetSecurity, 
	HANDLE &hThreadToken
)
{
	BOOL	result = TRUE;		// Default is success
	DWORD lastErr = 0;
	hThreadToken = NULL;			// Default assume we'll modify process token
	needToResetSecurity = false;	// Default assume we changed no privileges

	// Win9x has no security support
	if (IsNT ())
	{
		// Start by checking whether we are being impersonated.  On an NT4
		// box (which has no cloaking, and therefore cannot allow us to
		// pass on this impersonation to Winmgmt) we should RevertToSelf
		// if we have been configured to allow this.  If we haven't been
		// configured to allow this, bail out now.
		if (4 >= GetNTMajorVersion ())
		{
			if (OpenThreadToken (GetCurrentThread (), TOKEN_QUERY|TOKEN_IMPERSONATE, true, &hThreadToken))
			{
				// We are being impersonated
				if (s_bCanRevert)
				{
					if (result = RevertToSelf())
						needToResetSecurity = true;
				}
				else
				{
					// Error - cannot do this!  Time to bail out
					CloseHandle (hThreadToken);
					hThreadToken = NULL;
					result = FALSE;
				}
			}
		}
		else
		{
#ifdef WSCRPDEBUG
			HANDLE hToken = NULL;

			if (OpenThreadToken (GetCurrentThread (), TOKEN_QUERY, false, &hToken))
			{
				PrintPrivileges (hToken);
				CloseHandle (hToken);
			}
#endif
		}

		if (result)
		{
			// Now we check if we need to set privileges
			bool bIsUsingExplicitUserName = false;
		
			if (m_pProxyCache)
				bIsUsingExplicitUserName = m_pProxyCache->IsUsingExplicitUserName ();

			/*
			 * Specifying a user only makes sense for remote operations, and we
			 * don't need to mess with privilege for remote operations since
			 * they are set up by server logon anyway.
			 */
			if (!bIsUsingExplicitUserName && m_pPrivilegeSet)
			{
				// Nothing to do unless some privilege overrides have been set
				long lCount = 0;
				m_pPrivilegeSet->get_Count (&lCount);

				if (0 < lCount)
				{
					if (4 < GetNTMajorVersion ())
					{
						/*
						 * On NT5 we try to open the Thread token.  If the client app
						 * is calling into us on an impersonated thread (as IIS may be,
						 * for example), this will succeed.
						 */
						HANDLE hToken;
						SECURITY_IMPERSONATION_LEVEL secImpLevel = SecurityImpersonation;
						
						if (!(result =  OpenThreadToken (GetCurrentThread (), TOKEN_QUERY|TOKEN_DUPLICATE|TOKEN_IMPERSONATE, true, &hToken)))
						{
							// No thread token - go for the Process token instead
							HANDLE hProcess = GetCurrentProcess ();
							result = OpenProcessToken(hProcess, TOKEN_QUERY|TOKEN_DUPLICATE, &hToken);
							CloseHandle (hProcess);
						}
						else
						{
							// We are working with a thread token
							hThreadToken = hToken;		

							// Try and get the impersonation level of this token
							DWORD dwReturnLength  = 0;

							BOOL thisRes = GetTokenInformation (hToken, TokenImpersonationLevel, &secImpLevel, 
											sizeof (SECURITY_IMPERSONATION_LEVEL), &dwReturnLength);
						}

						if (result)
						{
							/*
							 * Getting here means we have a valid token, be it process or thread. We
							 * now attempt to duplicate it before Adjusting the Privileges.
							 */
#ifdef WSCRPDEBUG
							PrintPrivileges (hToken);
#endif
							HANDLE hDupToken;

							EnterCriticalSection (&g_csSecurity);

							result = s_pfnDuplicateTokenEx &&
								s_pfnDuplicateTokenEx (hToken, TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES|TOKEN_IMPERSONATE, NULL,
											secImpLevel, TokenImpersonation, &hDupToken);

							LeaveCriticalSection (&g_csSecurity);

							if (result)
							{
								CSWbemSecurity::AdjustTokenPrivileges (hDupToken, m_pPrivilegeSet);

								// Now use this token on the current thread
								if (SetThreadToken(NULL, hDupToken))
								{
									needToResetSecurity = true;
#ifdef WSCRPDEBUG
									CSWbemSecurity::PrintPrivileges (hDupToken);
#endif

									// Reset the blanket for the benefit of RPC
									DWORD	dwAuthnLevel, dwImpLevel;
									
									if (S_OK == GetAuthImp (m_pCurProxy, &dwAuthnLevel, &dwImpLevel))
									{
										// Force the cache to resecure the proxy
										IUnknown *pNewProxy = m_pProxyCache->GetProxy 
																((WbemAuthenticationLevelEnum) dwAuthnLevel, 
																 (WbemImpersonationLevelEnum) dwImpLevel, true);

										if (pNewProxy)
										{
											if (m_pCurProxy)
												m_pCurProxy->Release ();
											
											m_pCurProxy = pNewProxy;
										}
									}							
								}

								CloseHandle (hDupToken);
							}
							else
							{
								lastErr = GetLastError ();
							}
							
							/*
							 * If we are not using a thread token, close the token now. Otherwise
							 * the handle will be closed in the balanced call to RestorePrivileges ().
							 */
							if (!hThreadToken)
								CloseHandle (hToken);
						}
					}
					else
					{
						// For NT4 we adjust the privileges in the process token
						HANDLE hProcessToken = NULL;
						
						HANDLE hProcess = GetCurrentProcess ();
						result = OpenProcessToken(hProcess, TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES, &hProcessToken); 
						CloseHandle (hProcess);
						
						// Adjust privilege on the process
						if (result)
						{
#ifdef WSCRPDEBUG
							CSWbemSecurity::PrintPrivileges (hProcessToken);
#endif
							CSWbemSecurity::AdjustTokenPrivileges (hProcessToken, m_pPrivilegeSet);
#ifdef WSCRPDEBUG
							CSWbemSecurity::PrintPrivileges (hProcessToken);
#endif
							CloseHandle (hProcessToken);
						}
					}
				}
			}
		}
	}

	return result;
}

//***************************************************************************
//
//  SCODE CSWbemSecurity::ResetSecurity
//
//  DESCRIPTION:
//
//  Restore Privileges on the Thread Token.
//
//***************************************************************************

void	CSWbemSecurity::ResetSecurity (
	HANDLE hThreadToken
)
{
	// Win9x has no security palaver
	if (IsNT ())
	{
		/* 
		 * Set the supplied token (which may be NULL) into
		 * the current thread.
		 */
		BOOL result = SetThreadToken (NULL, hThreadToken);
		DWORD error = 0;

		if (!result)
			error = GetLastError ();
			
#ifdef WSCRPDEBUG
		// Print out the current privileges to see what's changed
		HANDLE hToken = NULL;

		if (!OpenThreadToken (GetCurrentThread (), TOKEN_QUERY, false, &hToken))
		{
			// No thread token - go for the Process token instead
			HANDLE hProcess = GetCurrentProcess ();
			OpenProcessToken(hProcess, TOKEN_QUERY, &hToken);
			CloseHandle (hProcess);
		}

		if (hToken)
		{
			PrintPrivileges (hToken);
			CloseHandle (hToken);
		}
#endif	
		if (hThreadToken)
				CloseHandle (hThreadToken);
	}
}

bool CSWbemSecurity::IsImpersonating (bool useDefaultUser, bool useDefaultAuthority)
{
	bool result = false;

	if (useDefaultUser && useDefaultAuthority && CSWbemSecurity::IsNT () && 
				(4 < CSWbemSecurity::GetNTMajorVersion ()))
	{
		// A suitable candidate - find out if we are running on an impersonated thread
		HANDLE hThreadToken = NULL;

		if (OpenThreadToken (GetCurrentThread (), TOKEN_QUERY, true, &hThreadToken))
		{
			// Check we have an impersonation token
			SECURITY_IMPERSONATION_LEVEL secImpLevel;

			DWORD dwReturnLength  = 0;
			if (GetTokenInformation (hThreadToken, TokenImpersonationLevel, &secImpLevel, 
									sizeof (SECURITY_IMPERSONATION_LEVEL), &dwReturnLength))
				result = ((SecurityImpersonation == secImpLevel) || (SecurityDelegation == secImpLevel));

			CloseHandle (hThreadToken);
		}
	}

	return result;
}

HRESULT CSWbemSecurity::GetAuthority (BSTR *bsAuthority)
{
	HRESULT hr = WBEM_E_FAILED;

	if (m_pProxyCache)
	{
		*bsAuthority = SysAllocString(m_pProxyCache->GetAuthority ());
		hr = S_OK;
	}

	return hr;
}

HRESULT CSWbemSecurity::GetUPD (BSTR *bsUser, BSTR *bsPassword, BSTR *bsDomain)
{
	HRESULT hr = WBEM_E_FAILED;

	if (m_pProxyCache)
	{
		COAUTHIDENTITY *pCoAuthIdentity = m_pProxyCache->GetCoAuthIdentity ();

		if (pCoAuthIdentity)
		{
			*bsUser = SysAllocString (pCoAuthIdentity->User);
			*bsPassword = SysAllocString (pCoAuthIdentity->Password);
			*bsDomain = SysAllocString (pCoAuthIdentity->Domain);
			WbemFreeAuthIdentity (pCoAuthIdentity);
		}
		
		hr = S_OK;
	}

	return hr;
}

HRESULT CSWbemSecurity::GetPrincipal (BSTR *bsPrincipal)
{
	HRESULT hr = WBEM_E_FAILED;

	if (m_pProxyCache)
	{
		*bsPrincipal = SysAllocString(m_pProxyCache->GetPrincipal ());
		hr = S_OK;
	}

	return hr;
}

// CWbemLocatorSecurity methods

//***************************************************************************
//
// CSWbemLocatorSecurity::CSWbemLocatorSecurity
//
// CONSTRUCTOR
//
//***************************************************************************

CWbemLocatorSecurity::CWbemLocatorSecurity (CSWbemPrivilegeSet *pPrivilegeSet) :
	m_cRef (1),
	m_impLevelSet (false),
	m_authnLevelSet (false),
	m_pPrivilegeSet (NULL)
{
	m_Dispatch.SetObj (this, IID_ISWbemSecurity, 
					CLSID_SWbemSecurity, L"SWbemSecurity");
	InterlockedIncrement(&g_cObj);

	if (pPrivilegeSet)
		m_pPrivilegeSet = new CSWbemPrivilegeSet (*pPrivilegeSet);
	else
		m_pPrivilegeSet = new CSWbemPrivilegeSet;
}

CWbemLocatorSecurity::CWbemLocatorSecurity (CWbemLocatorSecurity *pCWbemLocatorSecurity) :
	m_cRef (1),
	m_impLevelSet (false),
	m_authnLevelSet (false),
	m_pPrivilegeSet (NULL)
{
	m_Dispatch.SetObj (this, IID_ISWbemSecurity, 
					CLSID_SWbemSecurity, L"SWbemSecurity");
	InterlockedIncrement(&g_cObj);

	if (pCWbemLocatorSecurity)
	{
		m_pPrivilegeSet = new CSWbemPrivilegeSet (pCWbemLocatorSecurity->m_pPrivilegeSet);
		
		m_impLevelSet = pCWbemLocatorSecurity->m_impLevelSet;
		m_authnLevelSet = pCWbemLocatorSecurity->m_authnLevelSet;
		
		if (m_impLevelSet)
			m_impLevel = pCWbemLocatorSecurity->m_impLevel;

		if (m_authnLevelSet)
			m_authnLevel = pCWbemLocatorSecurity->m_authnLevel;
	}
	else
	{
		m_pPrivilegeSet = new CSWbemPrivilegeSet;
		m_impLevelSet = false;
		m_authnLevelSet = false;
	}
}

//***************************************************************************
//
// CWbemLocatorSecurity::CWbemLocatorSecurity
//
// DESTRUCTOR
//
//***************************************************************************

CWbemLocatorSecurity::~CWbemLocatorSecurity (void)
{
	InterlockedDecrement(&g_cObj);

	if (m_pPrivilegeSet)
		m_pPrivilegeSet->Release ();
}

//***************************************************************************
// HRESULT CWbemLocatorSecurity::QueryInterface
// long CWbemLocatorSecurity::AddRef
// long CWbemLocatorSecurity::Release
//
// DESCRIPTION:
//
// Standard Com IUNKNOWN functions.
//
//***************************************************************************

STDMETHODIMP CWbemLocatorSecurity::QueryInterface (

	IN REFIID riid,
    OUT LPVOID *ppv
)
{
    *ppv=NULL;

    if (IID_IUnknown==riid)
		*ppv = reinterpret_cast<IUnknown*>(this);
	else if (IID_ISWbemSecurity==riid)
		*ppv = (ISWbemSecurity *)this;
	else if (IID_IDispatch==riid)
        *ppv = (IDispatch *)this;
	else if (IID_ISupportErrorInfo==riid)
		*ppv = (ISupportErrorInfo *)this;
	else if (IID_IProvideClassInfo==riid)
		*ppv = (IProvideClassInfo *)this;

    if (NULL!=*ppv)
    {
        ((LPUNKNOWN)*ppv)->AddRef();
        return NOERROR;
    }

    return ResultFromScode(E_NOINTERFACE);
}

STDMETHODIMP_(ULONG) CWbemLocatorSecurity::AddRef(void)
{
    long l = InterlockedIncrement(&m_cRef);
    return l;
}

STDMETHODIMP_(ULONG) CWbemLocatorSecurity::Release(void)
{
    long l = InterlockedDecrement(&m_cRef);
    if (0L!=l)
        return l;
    delete this;
    return 0;
}

//***************************************************************************
// HRESULT CSWbemLocatorSecurity::InterfaceSupportsErrorInfo
//
// DESCRIPTION:
//
// Standard Com ISupportErrorInfo functions.
//
//***************************************************************************

STDMETHODIMP CWbemLocatorSecurity::InterfaceSupportsErrorInfo (IN REFIID riid)
{
	return (IID_ISWbemSecurity == riid) ? S_OK : S_FALSE;
}

//***************************************************************************
//
//  SCODE CWbemLocatorSecurity::get_AuthenticationLevel
//
//  DESCRIPTION:
//
//  Retrieve the authentication level
//
//  PARAMETERS:
//
//		pAuthenticationLevel		holds the value on return
//
//  RETURN VALUES:
//
//  WBEM_S_NO_ERROR				success
//	WBEM_E_INVALID_PARAMETER	bad input parameters
//  WBEM_E_FAILED				otherwise
//
//***************************************************************************

HRESULT CWbemLocatorSecurity::get_AuthenticationLevel (
	WbemAuthenticationLevelEnum *pAuthenticationLevel
)
{
	HRESULT hr = WBEM_E_FAILED;

	ResetLastErrors ();

	if (NULL == pAuthenticationLevel)
		hr = WBEM_E_INVALID_PARAMETER;
	else if (m_authnLevelSet)
	{
		*pAuthenticationLevel = m_authnLevel;
		hr = WBEM_S_NO_ERROR;
	}

	if (FAILED(hr))
		m_Dispatch.RaiseException (hr);

	return hr;
}

//***************************************************************************
//
//  SCODE CWbemLocatorSecurity::put_AuthenticationLevel
//
//  DESCRIPTION:
//
//  Set the authentication level
//
//  PARAMETERS:
//
//		authenticationLevel		the new value
//
//  RETURN VALUES:
//
//  WBEM_S_NO_ERROR				success
//	WBEM_E_INVALID_PARAMETER	bad input parameters
//  WBEM_E_FAILED				otherwise
//
//***************************************************************************

HRESULT CWbemLocatorSecurity::put_AuthenticationLevel (
	WbemAuthenticationLevelEnum authenticationLevel
)
{
	HRESULT hr = WBEM_E_FAILED;

	ResetLastErrors ();

	if ((WBEMS_MIN_AUTHN_LEVEL > authenticationLevel) || 
		(WBEMS_MAX_AUTHN_LEVEL < authenticationLevel))
		hr = WBEM_E_INVALID_PARAMETER;
	else 
	{
		m_authnLevel = authenticationLevel;
		m_authnLevelSet = true;
		hr = WBEM_S_NO_ERROR;
	}
 	
	if (FAILED(hr))
		m_Dispatch.RaiseException (hr);

	return hr;
}

//***************************************************************************
//
//  SCODE CWbemLocatorSecurity::get_ImpersonationLevel
//
//  DESCRIPTION:
//
//  Retrieve the impersonation level
//
//  PARAMETERS:
//
//		pImpersonationLevel		holds the value on return
//
//  RETURN VALUES:
//
//  WBEM_S_NO_ERROR				success
//	WBEM_E_INVALID_PARAMETER	bad input parameters
//  WBEM_E_FAILED				otherwise
//
//***************************************************************************

HRESULT CWbemLocatorSecurity::get_ImpersonationLevel (
	WbemImpersonationLevelEnum *pImpersonationLevel
)
{
	HRESULT hr = WBEM_E_FAILED;

	ResetLastErrors ();

	if (NULL == pImpersonationLevel)
		hr = WBEM_E_INVALID_PARAMETER;
	else if (m_impLevelSet)
	{
		*pImpersonationLevel = m_impLevel;
		hr = WBEM_S_NO_ERROR;
	}
	
	if (FAILED(hr))
		m_Dispatch.RaiseException (hr);

	return hr;
}

//***************************************************************************
//
//  SCODE CWbemLocatorSecurity::put_ImpersonationLevel
//
//  DESCRIPTION:
//
//  Set the impersonation level
//
//  PARAMETERS:
//
//		impersonationLevel		the new value
//
//  RETURN VALUES:
//
//  WBEM_S_NO_ERROR				success
//	WBEM_E_INVALID_PARAMETER	bad input parameters
//  WBEM_E_FAILED				otherwise
//
//***************************************************************************

HRESULT CWbemLocatorSecurity::put_ImpersonationLevel (
	WbemImpersonationLevelEnum impersonationLevel
)
{
	HRESULT hr = WBEM_E_FAILED;

	ResetLastErrors ();

	if ((WBEMS_MIN_IMP_LEVEL > impersonationLevel) || (WBEMS_MAX_IMP_LEVEL < impersonationLevel))
		hr = WBEM_E_INVALID_PARAMETER;
	else 
	{
		m_impLevel = impersonationLevel;
		m_impLevelSet = true;
		hr = WBEM_S_NO_ERROR;
	}
 	 		
	if (FAILED(hr))
		m_Dispatch.RaiseException (hr);

	return hr;
}

//***************************************************************************
//
//  SCODE CWbemLocatorSecurity::get_Privileges
//
//  DESCRIPTION:
//
//  Return the Privilege override set
//
//  WBEM_S_NO_ERROR				success
//	WBEM_E_INVALID_PARAMETER	bad input parameters
//  WBEM_E_FAILED				otherwise
//
//***************************************************************************

HRESULT CWbemLocatorSecurity::get_Privileges	(
	ISWbemPrivilegeSet **ppPrivileges
)
{
	HRESULT hr = WBEM_E_FAILED;

	ResetLastErrors ();

	if (NULL == ppPrivileges)
		hr = WBEM_E_INVALID_PARAMETER;
	{
		*ppPrivileges = NULL;

		if (m_pPrivilegeSet)
		{
			if (SUCCEEDED (m_pPrivilegeSet->QueryInterface (IID_ISWbemPrivilegeSet,
												(PPVOID) ppPrivileges)))
				hr = WBEM_S_NO_ERROR;
		}
	}
	
	if (FAILED(hr))
		m_Dispatch.RaiseException (hr);
			
	return hr;
}

//***************************************************************************
//
//  SCODE CWbemLocatorSecurity::SetSecurity
//
//  DESCRIPTION:
//
//  Set Privileges on the Process Token.
//
//***************************************************************************

BOOL CWbemLocatorSecurity::SetSecurity (
	BSTR bsUser,
	bool &needToResetSecurity,
	HANDLE &hThreadToken
)
{
	BOOL result = TRUE;
	needToResetSecurity = false;
	hThreadToken = NULL;

	/*
	 * NT5 supports the concept of dynamic cloaking, which means
	 * we can set privileges temporarily on a thread (impersonation)
	 * token basis immediately before a call to a remoted proxy.  
	 *
	 * Setting prior to locator.connectserver therefore makes no 
	 * sense for NT5.
	 *
	 * Oh and Win9x has no security support
	 */
	if (CSWbemSecurity::IsNT () && (4 >= CSWbemSecurity::GetNTMajorVersion ()))
	{
		/*
		 * Start by checking whether we are being impersonated.  On an NT4
		 * box (which has no cloaking, and therefore cannot allow us to
		 * pass on this impersonation to Winmgmt) we should RevertToSelf
		 * if we have been configured to allow this.  If we haven't been
		 * configured to allow this, bail out now.
		 */
		if (OpenThreadToken (GetCurrentThread (), TOKEN_QUERY|TOKEN_IMPERSONATE, false, &hThreadToken))
		{
			// We are being impersonated
			if (CSWbemSecurity::CanRevertToSelf ())
			{
				if (result = RevertToSelf())
					needToResetSecurity = true;
			}
			else
			{
				// Error - cannot do this!  Time to bail out
				CloseHandle (hThreadToken);
				hThreadToken = NULL;
				result = FALSE;
			}
		}

		if (result && m_pPrivilegeSet)
		{
			/*
			 * Specifying a user only makes sense for remote operations, and we
			 * don't need to mess with privilege for remote operations since
			 * they are set up by server logon anyway.
			 */
			if (!bsUser || (0 == wcslen(bsUser)))
			{
				// Nothing to do unless some privilege overrides have been set
				long lCount = 0;
				m_pPrivilegeSet->get_Count (&lCount);

				if (0 < lCount)
				{
					/*
					 * For NT4 privilege settings on impersonation tokens are ignored
					 * by DCOM/RPC.  Hence we have to set this on the process token.
					 *
					 * On NT4 we must set the configured privileges on the Process
					 * Token before the first call to RPC (i.e. IWbemLocator::ConnectServer)
					 * if we need to guarantee privilege settings will be communicated to
					 * the server.  
					 *
					 * This is because (a) NT4 does not support cloaking to allow the 
					 * impersonation (i.e. thread) token privilege setting to propagate
					 * on a per-DCOM call basis, (b) changes to Process-token level
					 * privileges _may_ be ignored after the first remote DCOM call due
					 * to RPC caching behavior.
					 *
					 * Note that this is a non-reversible operation, and is highly discouraged
					 * on apps (such as IE and IIS) which host multiple "tasks" since it adjusts
					 * the Privilege set for all of the other threads in the process.
					 */

					HANDLE hProcess = GetCurrentProcess ();
					HANDLE hProcessToken = NULL;
					result = OpenProcessToken(hProcess, TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES, &hProcessToken); 
					CloseHandle (hProcess);
					
					if (result)
					{
#ifdef WSCRPDEBUG
						CSWbemSecurity::PrintPrivileges (hProcessToken);
#endif
						CSWbemSecurity::AdjustTokenPrivileges (hProcessToken, m_pPrivilegeSet);
#ifdef WSCRPDEBUG
						CSWbemSecurity::PrintPrivileges (hProcessToken);
#endif
						CloseHandle (hProcessToken);
					}
				}
			}
		}
	}

	return result;
}

//***************************************************************************
//
//  SCODE CWbemLocatorSecurity::ResetSecurity
//
//  DESCRIPTION:
//
//  Restore Privileges on the Thread Token.
//
//***************************************************************************

void	CWbemLocatorSecurity::ResetSecurity (
	HANDLE hThreadToken
)
{
	// Win9x has no concept of impersonation
	// On NT5 we never set privileges through this class anyway
	if (CSWbemSecurity::IsNT () && (4 >= CSWbemSecurity::GetNTMajorVersion ()) 
				&& hThreadToken)
	{
		/* 
		 * Set the supplied token back into
		 * the current thread.
		 */
		BOOL result = SetThreadToken (NULL, hThreadToken);
		
#ifdef WSCRPDEBUG
		// Print out the current privileges to see what's changed
		HANDLE hToken = NULL;

		if (OpenThreadToken (GetCurrentThread (), TOKEN_QUERY, false, &hToken))
		{
			// No thread token - go for the Process token instead
			HANDLE hProcess = GetCurrentProcess ();
			OpenProcessToken(hProcess, TOKEN_QUERY, &hToken);
			CloseHandle (hProcess);
		}

		if (hToken)
		{
			CSWbemSecurity::PrintPrivileges (hToken);
			CloseHandle (hToken);
		}
#endif	
		CloseHandle (hThreadToken);
	}
}


#ifdef WSCRPDEBUG

//***************************************************************************
//
//  SCODE CSWbemSecurity::PrintPrivileges
//
//  DESCRIPTION:
//
//  Debug logging for privileges and other token info
//
//***************************************************************************

void CSWbemSecurity::PrintPrivileges (HANDLE hToken)
{
	DWORD dwSize = sizeof (TOKEN_PRIVILEGES);
	TOKEN_PRIVILEGES *tp = (TOKEN_PRIVILEGES *) new BYTE [dwSize];

	if (!tp)
	{
		return;
	}

	DWORD dwRequiredSize = 0;
	DWORD dwLastError = 0;
	FILE *fDebug = fopen ("C:/temp/wmidsec.txt", "a+");
	fprintf (fDebug, "\n\n***********************************************\n\n");
	bool status = false;

	// Step 0 - get impersonation level
	SECURITY_IMPERSONATION_LEVEL secImpLevel;
	if (GetTokenInformation (hToken, TokenImpersonationLevel, &secImpLevel, 
											sizeof (SECURITY_IMPERSONATION_LEVEL), &dwRequiredSize))
	{
		switch (secImpLevel)
		{
			case SecurityAnonymous:
				fprintf (fDebug, "IMPERSONATION LEVEL: Anonymous\n");
				break;
			
			case SecurityIdentification:
				fprintf (fDebug, "IMPERSONATION LEVEL: Identification\n");
				break;
			
			case SecurityImpersonation:
				fprintf (fDebug, "IMPERSONATION LEVEL: Impersonation\n");
				break;

			case SecurityDelegation:
				fprintf (fDebug, "IMPERSONATION LEVEL: Delegation\n");
				break;

			default:
				fprintf (fDebug, "IMPERSONATION LEVEL: Unknown!\n");
				break;
		}
	
		fflush (fDebug);
	}

	DWORD dwUSize = sizeof (TOKEN_USER);
	TOKEN_USER *tu = (TOKEN_USER *) new BYTE [dwUSize];

	if (!tu)
	{
		delete [] tp;
		fclose (fDebug);
		return;
	}

	// Step 1 - get user info
	if (0 ==  GetTokenInformation (hToken, TokenUser, 
						(LPVOID) tu, dwUSize, &dwRequiredSize))
	{
		delete [] tu;
		dwUSize = dwRequiredSize;
		dwRequiredSize = 0;
		tu = (TOKEN_USER *) new BYTE [dwUSize];

		if (!tu)
		{
			delete [] tp;
			fclose (fDebug);
			return;
		}

		if (!GetTokenInformation (hToken, TokenUser, (LPVOID) tu, dwUSize, 
							&dwRequiredSize))
			dwLastError = GetLastError ();
		else
			status = true;
	}

	if (status)
	{
		// Dig out the user info
		dwRequiredSize = BUFSIZ;
		char *userName = new char [dwRequiredSize];
		char *domainName = new char [dwRequiredSize];

		if (!userName || !domainName)
		{
			delete [] tp;
			delete [] tu;
			delete [] userName;
			delete [] domainName;
			return;
		}

		SID_NAME_USE eUse;

		LookupAccountSid (NULL, (tu->User).Sid, userName, &dwRequiredSize,
								domainName, &dwRequiredSize, &eUse);

		fprintf (fDebug, "USER: [%s\\%s]\n", domainName, userName);
		fflush (fDebug);
		delete [] userName;
		delete [] domainName;
	}
	else
	{
		fprintf (fDebug, " FAILED : %d\n", dwLastError);
		fflush (fDebug);
	}
	
	delete [] tu;
	status = false;
	dwRequiredSize = 0;

	// Step 2 - get privilege info
	if (0 ==  GetTokenInformation (hToken, TokenPrivileges, 
						(LPVOID) tp, dwSize, &dwRequiredSize))
	{
		delete [] tp;
		dwSize = dwRequiredSize;
		dwRequiredSize = 0;

		tp = (TOKEN_PRIVILEGES *) new BYTE [dwSize];

		if (!tp)
		{
			fclose (fDebug);
			return;
		}

		if (!GetTokenInformation (hToken, TokenPrivileges, 
						(LPVOID) tp, dwSize, &dwRequiredSize))
		{
			dwLastError = GetLastError ();
		}
		else
			status = true;
	}
	else
		status = true;

	if (status)
	{
		fprintf (fDebug, "PRIVILEGES: [%d]\n", tp->PrivilegeCount);
		fflush (fDebug);
	
		for (DWORD i = 0; i < tp->PrivilegeCount; i++)
		{
			DWORD dwNameSize = 256;
			LPTSTR name = new TCHAR [dwNameSize + 1];

			if (!name)
			{
				delete [] tp;
				fclose (fDebug);
				return;
			}

			DWORD dwRequiredSize = dwNameSize;

			if (LookupPrivilegeName (NULL, &(tp->Privileges [i].Luid), name, &dwRequiredSize))
			{
				BOOL enabDefault = (tp->Privileges [i].Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT);
				BOOL enabled = (tp->Privileges [i].Attributes & SE_PRIVILEGE_ENABLED);
				BOOL usedForAccess (tp->Privileges [i].Attributes & SE_PRIVILEGE_USED_FOR_ACCESS);

				fprintf (fDebug, " %s: enabledByDefault=%d enabled=%d usedForAccess=%d\n", 
							name, enabDefault, enabled, usedForAccess);
				fflush (fDebug);
			}
			else
			{
				dwLastError = GetLastError ();
				delete [] name;
				dwNameSize = dwRequiredSize;
				name = new TCHAR [dwRequiredSize];

				if (!name)
				{
					delete [] tp;
					fclose (fDebug);
					return;
				}

				if (LookupPrivilegeName (NULL, &(tp->Privileges [i].Luid), name, &dwRequiredSize))
				{
					BOOL enabDefault = (tp->Privileges [i].Attributes & SE_PRIVILEGE_ENABLED_BY_DEFAULT);
					BOOL enabled = (tp->Privileges [i].Attributes & SE_PRIVILEGE_ENABLED);
					BOOL usedForAccess (tp->Privileges [i].Attributes & SE_PRIVILEGE_USED_FOR_ACCESS);
					fprintf (fDebug, " %s: enabledByDefault=%d enabled=%d usedForAccess=%d\n", 
							name, enabDefault, enabled, usedForAccess);
					fflush (fDebug);
				}
				else
					dwLastError = GetLastError ();
			}

			delete [] name;
		}
	}
	else
	{
		fprintf (fDebug, " FAILED : %d\n", dwLastError);
		fflush (fDebug);
	}

	delete [] tp;
	fclose (fDebug);
}

#endif