//***************************************************************************

//

// Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
//
//***************************************************************************
#include "wmicom.h"
#include "wmimof.h"
#include "wmimap.h"
#include <stdlib.h>
#include <winerror.h>
#include <TCHAR.h>

////////////////////////////////////////////////////////////////////////////////////////////////
//**********************************************************************************************
//  Global Utility Functions
//**********************************************************************************************
////////////////////////////////////////////////////////////////////////////////////////////////
BOOL IsBinaryMofResourceEvent(LPOLESTR pGuid, GUID gGuid)
{
	HRESULT hr;
	GUID Guid;

	hr = CLSIDFromString(pGuid,&Guid);
	if( SUCCEEDED(hr) )
    {
		if( gGuid == Guid)
        {
			return TRUE;
		}
	}

    return FALSE;
}
/////////////////////////////////////////////////////////////////////
BOOL GetParsedPropertiesAndClass( BSTR Query,WCHAR * wcsClass )
{
	ParsedObjectPath   * pParsedPath = NULL;										// stdlibrary API
	CObjectPathParser   Parser;	
    BOOL fRc = FALSE;

    if( CObjectPathParser::NoError == Parser.Parse(Query, &pParsedPath))
    {
        try
        {
			// NTRaid:136400
			// 07/12/00
            if(pParsedPath && !IsBadReadPtr( pParsedPath, sizeof(ParsedObjectPath)))
            {
            	KeyRef * pKeyRef = NULL;
        	    pKeyRef = *(pParsedPath->m_paKeys);
                if(!IsBadReadPtr( pKeyRef, sizeof(KeyRef)))
                {
                    wcscpy(wcsClass,pParsedPath->m_pClass);
                    fRc = TRUE;
                }
            }

  	        Parser.Free(pParsedPath);
        }
        catch(...)
        {
            Parser.Free(pParsedPath);
            throw;
        }
    }

    return fRc;
}
////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CheckIfThisIsAValidKeyProperty(WCHAR * wcsClass, WCHAR * wcsProperty, IWbemServices * p)
{
	HRESULT hr = WBEM_E_FAILED;
	IWbemClassObject * pIHCO = NULL;
    IWbemQualifierSet * pIWbemQualifierSet = NULL;
    long lType = 0L;
	BSTR strPath = NULL;


	strPath = SysAllocString(wcsClass);
	if(strPath == NULL)
	{
		hr = E_OUTOFMEMORY;
	}
	else
	{
		hr = p->GetObject(strPath, 0,NULL, &pIHCO, NULL);
		SysFreeString(strPath);
		if (WBEM_S_NO_ERROR != hr)
			return WBEM_E_INVALID_CLASS;

		if(wcsProperty){
			hr = pIHCO->GetPropertyQualifierSet(wcsProperty,&pIWbemQualifierSet);
			if( SUCCEEDED(hr) ){

           		CVARIANT v;
	    		hr = pIWbemQualifierSet->Get(L"key", 0, &v, 0);
				SAFE_RELEASE_PTR(pIWbemQualifierSet);
			}
			else{
				hr = WBEM_E_INVALID_OBJECT_PATH;
			}
		}

		//============================================================
		//  Cleanup
		//============================================================
		SAFE_RELEASE_PTR(pIHCO);
	}
	return hr;

}
//====================================================================
HRESULT GetParsedPath( BSTR ObjectPath,WCHAR * wcsClass, WCHAR * wcsInstance,IWbemServices * p )
{
    //============================================================
	//  Get the path and instance name and check to make sure it
    //  is valid
	//============================================================
	ParsedObjectPath   * pParsedPath = NULL;										// stdlibrary API
	CObjectPathParser   Parser;	
    HRESULT hr = WBEM_E_FAILED;

    if( 0 == Parser.Parse(ObjectPath, &pParsedPath))
    {
        try
        {
			// NTRaid:136395
			// 07/12/00
            if(pParsedPath && !IsBadReadPtr( pParsedPath, sizeof(ParsedObjectPath)))
            {
            	KeyRef * pKeyRef = NULL;
                pKeyRef = *(pParsedPath->m_paKeys);
                if( !IsBadReadPtr( pKeyRef, sizeof(KeyRef)))
                {
                    hr = CheckIfThisIsAValidKeyProperty(pParsedPath->m_pClass, pKeyRef->m_pName,p );
			        if( SUCCEEDED(hr) )
                    {
				        wcscpy(wcsClass,pParsedPath->m_pClass);
				        wcscpy(wcsInstance,pKeyRef->m_vValue.bstrVal);
			        }
                }
            }
  	        Parser.Free(pParsedPath);
        }
        catch(...)
        {
            hr = WBEM_E_UNEXPECTED;
            Parser.Free(pParsedPath);
            throw;
        }
    }
    return hr;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL GetUserThreadToken(HANDLE * phThreadTok)
{
    BOOL fRc = FALSE;

	HRESULT hRes = WbemCoImpersonateClient();
    if (SUCCEEDED(hRes))
    {
		// Now, let's check the impersonation level.  First, get the thread token
        if (!OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, phThreadTok))
        {
            // If the CoImpersonate works, but the OpenThreadToken fails, we are running under the
            // process token (either local system, or if we are running with /exe, the rights of
            // the logged in user).  In either case, impersonation rights don't apply.  We have the
            // full rights of that user.

             if(GetLastError() == ERROR_NO_TOKEN)
             {
                // Try getting the thread token.  If it fails it's because we're a system thread and
                // we don't yet have a thread token, so just impersonate self and try again.
                if( ImpersonateSelf(SecurityImpersonation) )
                {
                    if (!OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, phThreadTok))
                    {
                        fRc = FALSE;
                    }
                    else
                    {
                        fRc = TRUE;
                    }
                }
                else
                {
                    ERRORTRACE((THISPROVIDER,"ImpersonateSelf(SecurityImpersonation)failed"));
                }
            }
         }
         else
         {
             fRc = TRUE;
         }
	}
    if( !fRc )
    {
	    ERRORTRACE((THISPROVIDER,IDS_ImpersonationFailed));
    }
    return fRc;
}
////////////////////////////////////////////////////////////////////////////////////////////////

SAFEARRAY * OMSSafeArrayCreate( IN VARTYPE vt, IN int iNumElements)
{
    if(iNumElements < 1)
    {
        return NULL;
    }
    SAFEARRAYBOUND rgsabound[1];
    rgsabound[0].lLbound = 0;
    rgsabound[0].cElements = iNumElements;
    return SafeArrayCreate(vt,1,rgsabound);
}
////////////////////////////////////////////////////////////////////////////////////////////////
void TranslateAndLog( WCHAR * wcsMsg )
{
    CAnsiUnicode XLate;
    char * pStr = NULL;

	if( SUCCEEDED(XLate.UnicodeToAnsi(wcsMsg,pStr)))
    {
		ERRORTRACE((THISPROVIDER,pStr));
   		ERRORTRACE((THISPROVIDER,"\n"));
        SAFE_DELETE_ARRAY(pStr);
	}
}
/////////////////////////////////////////////////////////////////////////////////////////////////
bool IsNT(void)
{
    OSVERSIONINFO os;
    os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    if(!GetVersionEx(&os))
        return FALSE;           // should never happen
    return os.dwPlatformId == VER_PLATFORM_WIN32_NT;
}
////////////////////////////////////////////////////////////////////
BOOL SetGuid(WCHAR * pwcsGuidString, CLSID & Guid)
{
	BOOL fRc = FALSE;
    CAutoWChar wcsGuid(MAX_PATH+2);

	if( wcsGuid.Valid() )
	{
		fRc = TRUE;
		swprintf(wcsGuid,L"{%s}",pwcsGuidString );		

		if(FAILED(CLSIDFromString(wcsGuid, &Guid)))
		{
			if( FAILED(CLSIDFromString(pwcsGuidString, &Guid)))
			{
				fRc = FALSE;
			}
		}	
	}
    return fRc;
}
////////////////////////////////////////////////////////////////////
HRESULT AllocAndCopy(WCHAR * wcsSource, WCHAR ** pwcsDest )
{
    HRESULT hr = WBEM_E_FAILED;

    int nLen = wcslen(wcsSource);
    if( nLen > 0 )
    {
       *pwcsDest = new WCHAR[nLen + 2 ];
       if( *pwcsDest )
       {
          wcscpy(*pwcsDest,wcsSource);
          hr = S_OK;
       }
    }

    return hr;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//**********************************************************************************************
//  Utility Classes
//**********************************************************************************************
////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
void _WMIHandleMap::AddRef()
{
  InterlockedIncrement((long*)&RefCount);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
long _WMIHandleMap::Release()
{
  	ULONG cRef = InterlockedDecrement( (long*) &RefCount);
	if ( !cRef ){
        WmiCloseBlock(WMIHandle);
		return 0;
	}
	return cRef;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
_WMIEventRequest::_WMIEventRequest()
{
    pwcsClass = NULL ;
    pHandler = NULL;
    pServices = NULL;
    pCtx = NULL;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
_WMIEventRequest::~_WMIEventRequest()
{
    SAFE_RELEASE_PTR(pServices);
    SAFE_RELEASE_PTR(pCtx);
    SAFE_DELETE_ARRAY(pwcsClass);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
void _WMIEventRequest::AddPtrs( IWbemObjectSink __RPC_FAR * Handler,IWbemServices __RPC_FAR * Services,IWbemContext __RPC_FAR * Ctx)
{
    pHandler = Handler;
    pServices = Services;
    pCtx = Ctx;
    if( pServices ){
        pServices->AddRef();
    }
    if( pCtx ){
        pCtx->AddRef();
    }
    return;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
_AccessList::~_AccessList()
{
    for( int i = 0; i < m_List.Size(); i++ )
    {
        IWbemObjectAccess * pPtr = (IWbemObjectAccess *)m_List[i];
        SAFE_RELEASE_PTR(pPtr);
    }
    m_List.Empty();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
_IdList::~_IdList()
{
    for( int i = 0; i < m_List.Size(); i++ )
    {
        ULONG_PTR* pPtr = (ULONG_PTR*)m_List[i];
        SAFE_DELETE_PTR(pPtr);
    }
    m_List.Empty();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
_HandleList::~_HandleList()
{
    for( int i = 0; i < m_List.Size(); i++ )
    {
        HANDLE * pPtr = (HANDLE*)m_List[i];
        SAFE_DELETE_PTR(pPtr);
    }
    m_List.Empty();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
_InstanceList::~_InstanceList()
{
    for( int i = 0; i < m_List.Size(); i++ )
    {
        WCHAR * p = (WCHAR*)m_List[i];
        SAFE_DELETE_ARRAY(p);
    }
    m_List.Empty();
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
_OldClassInfo::~_OldClassInfo()
{
     SAFE_DELETE_ARRAY(m_pClass);
     SAFE_DELETE_ARRAY(m_pPath);
     m_pClass = m_pPath = NULL;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
_OldClassList::~_OldClassList()
{
    for( int i = 0; i < m_List.Size(); i++ )
    {
        OldClassInfo * p = (OldClassInfo*)m_List[i];
        SAFE_DELETE_PTR(p);
    }
    m_List.Empty();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
_WMIHiPerfHandleMap::_WMIHiPerfHandleMap(CWMIProcessClass * p, IWbemHiPerfEnum * pEnum)
{
    m_pEnum = pEnum;
    if( pEnum )
    {
        pEnum->AddRef();
    }
    m_pClass = p;
    m_fEnumerator = FALSE;
    lHiPerfId = 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
_WMIHiPerfHandleMap::~_WMIHiPerfHandleMap()
{
    SAFE_RELEASE_PTR(m_pEnum);
    lHiPerfId = 0;
    SAFE_DELETE_PTR(m_pClass);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//  Hi Perf Handle Map = Handles are addref'd and when released, then the block is closed
//  Critical Sections are handled elsewhere
///////////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CHiPerfHandleMap::Add( HANDLE hCurrent, ULONG_PTR lHiPerfId, CWMIProcessClass * p, IWbemHiPerfEnum * pEnum)
{
    HRESULT hr = S_OK;

	WMIHiPerfHandleMap * pWMIMap = new WMIHiPerfHandleMap(p,pEnum);
    if( pWMIMap )
    {
        try
        {
    	    pWMIMap->WMIHandle = hCurrent;
            pWMIMap->lHiPerfId = lHiPerfId;
			// 170635
 	        if(CFlexArray::out_of_memory == m_List.Add(pWMIMap))
			{
				SAFE_DELETE_PTR(pWMIMap);
				hr = E_OUTOFMEMORY;
			}
        }
        catch(...)
        {
            hr = WBEM_E_UNEXPECTED;
            SAFE_DELETE_PTR(pWMIMap);
            throw;
        }
	}

    return hr;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CHiPerfHandleMap::FindHandleAndGetClassPtr( HANDLE & hCurrent, ULONG_PTR lHiPerfId,CWMIProcessClass *& p)
{
    HRESULT hr = WBEM_E_NOT_FOUND;

    for( int i=0; i<m_List.Size(); i++)
    {
        //===================================================
        //
        //===================================================
        WMIHiPerfHandleMap * pMap = (WMIHiPerfHandleMap *) m_List[i];
        if( pMap->lHiPerfId == lHiPerfId )
        {
            hCurrent = pMap->WMIHandle;
            p = pMap->m_pClass;
            hr = S_OK;
        }
    }

    return hr;

}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CHiPerfHandleMap::GetFirstHandle(HANDLE & hCurrent,CWMIProcessClass *& p, IWbemHiPerfEnum *& pEnum)
{
    m_nIndex=0;
    return GetNextHandle(hCurrent,p,pEnum);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CHiPerfHandleMap::GetNextHandle(HANDLE & hCurrent,CWMIProcessClass *& p, IWbemHiPerfEnum *& pEnum)
{
    HRESULT hr = WBEM_S_NO_MORE_DATA;

    if( m_nIndex < m_List.Size() )
    {
        WMIHiPerfHandleMap * pMap = (WMIHiPerfHandleMap *) m_List[m_nIndex];
        hCurrent = pMap->WMIHandle;
        p = pMap->m_pClass;
        pEnum = pMap->m_pEnum;
        m_nIndex++;
        hr = S_OK;
    }
    return hr;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////

HRESULT CHiPerfHandleMap::Delete( HANDLE & hCurrent, ULONG_PTR lHiPerfId )
{
    HRESULT hr = WBEM_E_NOT_FOUND;

    for( int i=0; i<m_List.Size(); i++)
    {
        //===================================================
        //
        //===================================================
        WMIHiPerfHandleMap * pMap = (WMIHiPerfHandleMap *) m_List[i];
        if( pMap->lHiPerfId == lHiPerfId )
        {
            hCurrent = pMap->WMIHandle;
            SAFE_DELETE_PTR(pMap);
            m_List.RemoveAt(i);
            hr = S_OK;
            break;
        }
    }

    return hr;
}


////////////////////////////////////////////////////////////////////////////////////////////////
//  When this function is called, release all the handles kept
// THis function is called in the destructor of the class to release all teh WMIHiPerfHandleMap
// classes allocated
////////////////////////////////////////////////////////////////////////////////////////////////
void CHiPerfHandleMap::CloseAndReleaseHandles()
{
	//===================================
	//  Go through the handles one at
	//  a time and close them, then
	//  delete the records from the
	//  array
	//===================================

    CAutoBlock((CCriticalSection *)&m_HandleCs);

    if( m_List.Size() > 0 ){

        for(int i = 0; i < m_List.Size(); i++){
    		
		    WMIHiPerfHandleMap * pWMIMap = (WMIHiPerfHandleMap *) m_List[i];
            SAFE_DELETE_PTR(pWMIMap);
	    }

	    //==================================================
	    //  Remove it and deallocate memory
	    //==================================================
        m_List.Empty();
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
//  Regular Handle Map = Expensize handles are always kept open - by default we, dont' know the lifetime
//  of these handles
///////////////////////////////////////////////////////////////////////////////////////////////////////////

HRESULT CHandleMap::Add(CLSID Guid, HANDLE hCurrent, ULONG uDesiredAccess)
{
    // Critical section is called elsewhere

    HRESULT hr = S_OK;

	WMIHandleMap * pWMIMap = new WMIHandleMap();
    if( pWMIMap )
    {
	    try
        {
            pWMIMap->AddRef();                          // Used for HiPerf counts, otherwise not referenced
    		pWMIMap->WMIHandle = hCurrent;
		    pWMIMap->Guid = Guid;
		    pWMIMap->uDesiredAccess = uDesiredAccess;

			// 170635
		    if(CFlexArray::out_of_memory == m_List.Add(pWMIMap))
			{
				hr = E_OUTOFMEMORY;
				SAFE_DELETE_PTR(pWMIMap);
			}
	    }
        catch(...)
        {
            hr = WBEM_E_UNEXPECTED;
            SAFE_DELETE_PTR(pWMIMap);
            throw;
        }
    }
    return hr;
}
////////////////////////////////////////////////////////////////////////////////////////////////
int CHandleMap::ExistingHandleAlreadyExistsForThisGuidUseIt(CLSID Guid,
                                                            HANDLE & hCurrentWMIHandle,
                                                            BOOL & fCloseHandle,
                                                            ULONG uDesiredAccess)
{
	int nRc = ERROR_NOT_SUPPORTED;

    // Critical section is called elsewhere

	//=====================================================
	//  Initialize stuff
	//=====================================================
	hCurrentWMIHandle = 0;
	fCloseHandle = TRUE;

    for(int i = 0; i < m_List.Size(); i++){
    		
		WMIHandleMap * pWMIMap = (WMIHandleMap*) m_List[i];
		//==================================================
		//  Compare and see if this guid already has a
		//  handle assigned for it with the access permissions
		//  that we want to use
		//==================================================
		if( pWMIMap->Guid == Guid ){
			if( pWMIMap->uDesiredAccess == uDesiredAccess ){

				hCurrentWMIHandle = pWMIMap->WMIHandle;
                pWMIMap->AddRef();                      // Used for HiPerf Handles, otherwise not needed
				nRc = ERROR_SUCCESS;
				fCloseHandle = FALSE;
				break;
			}
		}
    }

	return nRc;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//  When this function is called, we need to close all of the handles that may have been kept
//  open for accumulation purposes
////////////////////////////////////////////////////////////////////////////////////////////////
void CHandleMap::CloseAllOutstandingWMIHandles()
{
	//===================================
	//  Go through the handles one at
	//  a time and close them, then
	//  delete the records from the
	//  array
	//===================================

    CAutoBlock((CCriticalSection *)&m_HandleCs);

    if( m_List.Size() > 0 ){

        for(int i = 0; i < m_List.Size(); i++){
    		
		    WMIHandleMap * pWMIMap = (WMIHandleMap*) m_List[i];
		    //==================================================
		    //  Inform WMI we are done with this guy
		    //==================================================
            try
            {
		        WmiCloseBlock(pWMIMap->WMIHandle);
            }
            catch(...)
            {
                // don't throw
            }
            SAFE_DELETE_PTR(pWMIMap);
	    }

	    //==================================================
	    //  Remove it and deallocate memory
	    //==================================================
        m_List.Empty();
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////
//  Used when we know the handles lifetimes
////////////////////////////////////////////////////////////////////////////////////////////////
int CHandleMap::ReleaseHandle( HANDLE hCurrentWMIHandle )
{
	int nRc = ERROR_NOT_SUPPORTED;

    CAutoBlock((CCriticalSection *)&m_HandleCs);

    for(int i = 0; i < m_List.Size(); i++){
    		
		WMIHandleMap * pWMIMap = (WMIHandleMap*) m_List[i];

        if( pWMIMap->WMIHandle == hCurrentWMIHandle )
        {
            long RefCount = pWMIMap->Release();                      // Used for HiPerf Handles, otherwise not needed
            if( !RefCount )
            {
//                WmiCloseBlock(hCurrentWMIHandle);
                SAFE_DELETE_PTR( pWMIMap);
                m_List.RemoveAt(i);
            }
			nRc = ERROR_SUCCESS;
			break;
		}
    }

	return nRc;
}
////////////////////////////////////////////////////////////////////////////////////////////////
int CHandleMap::GetHandle(CLSID Guid, HANDLE & hCurrentWMIHandle )
{
	int nRc = ERROR_NOT_SUPPORTED;

    CAutoBlock((CCriticalSection *)&m_HandleCs);

	//=====================================================
	//  Initialize stuff
	//=====================================================
	hCurrentWMIHandle = 0;

    for(int i = 0; i < m_List.Size(); i++){
    		
		WMIHandleMap * pWMIMap = (WMIHandleMap*) m_List[i];
		if( pWMIMap->Guid == Guid ){

			hCurrentWMIHandle = pWMIMap->WMIHandle;
            pWMIMap->AddRef();                      // Used for HiPerf Handles, otherwise not needed
			nRc = ERROR_SUCCESS;
			break;
		}
    }

	return nRc;
}


////////////////////////////////////////////////////////////////////////////////////////////////
//**********************************************************************************************
//  Utility Classes:  CANSIUNICODE
//**********************************************************************************************
////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CAnsiUnicode::AllocateAndConvertAnsiToUnicode(char * pstr, WCHAR *& pszW)
{
    HRESULT hr = WBEM_E_FAILED;
    pszW = NULL;

    int nSize = strlen(pstr);
    if (nSize != 0 ){

        // Determine number of wide characters to be allocated for the
        // Unicode string.
        nSize++;
		pszW = new WCHAR[nSize * 2];
		if (NULL != pszW){
    		try
            {
                // Covert to Unicode.
				MultiByteToWideChar(CP_ACP, 0, pstr, nSize,pszW,nSize);
                hr = S_OK;
	        }	
            catch(...)
            {
                SAFE_DELETE_ARRAY(pszW);
                hr = WBEM_E_UNEXPECTED;
                throw;
            }
		}
    }
    return hr;
}
////////////////////////////////////////////////////////////////////
HRESULT CAnsiUnicode::UnicodeToAnsi(WCHAR * pszW, char *& pAnsi)
{
    ULONG cbAnsi, cCharacters;
    HRESULT hr = WBEM_E_FAILED;

    pAnsi = NULL;
    if (pszW != NULL){

        cCharacters = wcslen(pszW)+1;
        // Determine number of bytes to be allocated for ANSI string. An
        // ANSI string can have at most 2 bytes per character (for Double
        // Byte Character Strings.)
        cbAnsi = cCharacters*2;
		pAnsi = new char[cbAnsi];
		if (NULL != pAnsi)
        {
		    try
            {
				// Convert to ANSI.
				if (0 != WideCharToMultiByte(CP_ACP, 0, pszW, cCharacters, pAnsi, cbAnsi, NULL, NULL)){
					hr = S_OK;
	            }
		    }
            catch(...)
            {
                SAFE_DELETE_ARRAY(pAnsi);
                hr = WBEM_E_UNEXPECTED;
                throw;
            }
        }

    }
    return hr;
}
//************************************************************************************************************
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//   CWMIManagement
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//************************************************************************************************************
CWMIManagement::CWMIManagement( )
{
    m_pHandler = NULL;
    m_pServices = NULL;
    m_pCtx = NULL;
    m_pHandleMap = NULL;
}
//////////////////////////////////////////////////////////////////////////////////////
CWMIManagement::~CWMIManagement()
{
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CWMIManagement::SendPrivilegeExtendedErrorObject( HRESULT hrToReturn,WCHAR * wcsClass)
{
	HRESULT hr,hRes;
	IWbemClassObject * pClass = NULL, *pInst=NULL;
    BOOL fSetStatus = FALSE;


	if( hrToReturn == WBEM_E_ACCESS_DENIED ){

		TOKEN_PRIVILEGES * ptPriv = NULL;

		hr = GetListOfUserPrivileges(ptPriv);
		if( SUCCEEDED(hr ) ){
			
			BSTR strPrivelegeStat = NULL;
			strPrivelegeStat = SysAllocString(L"Win32_PrivilegesStatus");
			if(strPrivelegeStat != NULL)
			{
				hr = m_pServices->GetObject(strPrivelegeStat, 0,m_pCtx, &pClass, NULL);
				if( hr == S_OK){	

					//=============================================================
					// Get an instance of the extended class
					//=============================================================
					hr = pClass->SpawnInstance(0,&pInst);
					SAFE_RELEASE_PTR(pClass);
			
					if( pInst ){

						CVARIANT varTmp;
						WCHAR * pwcsStr = NULL;
						CAnsiUnicode XLate;
						//=========================================================
						//  Fill in description
						//=========================================================
						XLate.AllocateAndConvertAnsiToUnicode(IDS_ImpersonationFailed,pwcsStr);
						varTmp.SetStr(pwcsStr);
						hr = pInst->Put(L"Description", 0, &varTmp, NULL);
						SAFE_DELETE_ARRAY( pwcsStr );

						//======================================================
						//  Initialize all of the necessary stuff and get the
						//  definition of the class we are working with
						//======================================================
						CWMIProcessClass ClassInfo(0);
						if( SUCCEEDED(ClassInfo.Initialize()) )
						{
							ClassInfo.WMI()->SetWMIPointers(m_pHandleMap,m_pServices,m_pHandler,m_pCtx);
							ClassInfo.SetClass(wcsClass);
							SAFEARRAY *psaPrivNotHeld=NULL;
							SAFEARRAY *psaPrivReq=NULL;

							//=========================================================
							// Get PrivilegesRequired
							// The only place to get this, if possible, is from the
							// class
							//=========================================================
					
							hRes = ClassInfo.GetPrivilegesQualifer(&psaPrivReq);
							if( hRes == WBEM_S_NO_ERROR){

								//=========================================================
								// Get PrivilegesNotHeld
								//=========================================================
								ProcessPrivileges(ptPriv,psaPrivNotHeld,psaPrivReq);
								//=========================================================
								//  Send it off
								//=========================================================
								VARIANT v;

								if( psaPrivReq ){
									VariantInit(&v);
									SAFEARRAY *pSafeArray = NULL;

									if ( SUCCEEDED ( SafeArrayCopy ((SAFEARRAY*)psaPrivReq , &pSafeArray ) ) ){
        								v.vt = VT_BSTR | VT_ARRAY;
	        							v.parray = pSafeArray;
										pInst->Put(L"PrivilegesRequired", 0, &v, NULL);
										VariantClear(&v);
									}
								}

								if( psaPrivNotHeld ){
									VariantInit(&v);
									SAFEARRAY *pSafeArray = NULL;

									if ( SUCCEEDED ( SafeArrayCopy ((SAFEARRAY*)psaPrivNotHeld , &pSafeArray ) ) ){
        								v.vt = VT_BSTR | VT_ARRAY;
	        							v.parray = pSafeArray;
										pInst->Put(L"PrivilegesNotHeld", 0, &v, NULL);
										VariantClear(&v);
									}
								}
							}
							//=========================================================
							// Now, send this guy off...
							//=========================================================
							fSetStatus = TRUE;
							hr = m_pHandler->SetStatus(0,hrToReturn,NULL,pInst);


							if (psaPrivNotHeld)
								SafeArrayDestroy(psaPrivNotHeld);
							if (psaPrivReq)
								SafeArrayDestroy(psaPrivReq);
						}

					}
					SAFE_RELEASE_PTR(pInst);
				}	
				SysFreeString(strPrivelegeStat);
			}						
		}

        SAFE_DELETE_ARRAY(ptPriv);
	}

    if( !fSetStatus ){
        hr = m_pHandler->SetStatus(0,hrToReturn,NULL,NULL);
    }
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CWMIManagement::SetErrorMessage(HRESULT hrToReturn,WCHAR * wcsClass,WCHAR * wcsMsg)
{
	HRESULT hr;
	IWbemClassObject * pClass = NULL, *pInst=NULL;
    BOOL fSetStatus = FALSE;

    if( m_pHandler )
    {
		BSTR strExtendedStat = NULL;

	    switch( hrToReturn ){

		    case WBEM_E_ACCESS_DENIED:
			    SendPrivilegeExtendedErrorObject(hrToReturn,wcsClass);
			    break;

		    case S_OK :
		        hr = m_pHandler->SetStatus(0,hrToReturn,NULL,NULL);
			    break;

		    default:
				strExtendedStat = SysAllocString(L"__ExtendedStatus");
				if(strExtendedStat != NULL)
				{
					hr = m_pServices->GetObject(strExtendedStat, 0,m_pCtx, &pClass, NULL);
					if( hr == S_OK){	
						hr = pClass->SpawnInstance(0,&pInst);
						if( pInst ){

							CVARIANT varTmp;
							varTmp.SetStr(wcsMsg);
				
							hr = pInst->Put(L"Description", 0, &varTmp, NULL);
							hr = m_pHandler->SetStatus(0,hrToReturn,NULL,pInst);
							fSetStatus = TRUE;

							// Now log the error in the error log
							if( hrToReturn != S_OK ){
								TranslateAndLog(varTmp.GetStr());
							}
						}		
					}
					if( !fSetStatus ){
    					hr = m_pHandler->SetStatus(0,hrToReturn,NULL,NULL);
					}
					SAFE_RELEASE_PTR(pClass);
					SAFE_RELEASE_PTR(pInst);
					SysFreeString(strExtendedStat);
				}
				else
				{
					hr = E_OUTOFMEMORY;
				}
			    break;
	    }
    }
    return hrToReturn;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT CWMIManagement::GetListOfUserPrivileges(TOKEN_PRIVILEGES *& ptPriv)
{
	HRESULT hr = WBEM_E_FAILED;

	//  Get the privileges this user has
	DWORD dwTokenInfoLength = 0;
	DWORD dwSize = 0;
	HANDLE hThreadTok;
	
    if (IsNT()){

		if( GetUserThreadToken(&hThreadTok) ){

		 // get information
			if (!GetTokenInformation(hThreadTok, TokenPrivileges, NULL, dwTokenInfoLength, &dwSize)){
				if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){
    				ptPriv = new TOKEN_PRIVILEGES[dwSize+2];
                    if( ptPriv )
                    {
					    try
                        {
						    dwTokenInfoLength = dwSize;
							if(GetTokenInformation(hThreadTok, TokenPrivileges, (LPVOID)ptPriv, dwTokenInfoLength, &dwSize))
                            {
								hr = WBEM_NO_ERROR;
							}
						}
                        catch(...)
                        {
                            SAFE_DELETE_ARRAY(ptPriv);
                            hr = WBEM_E_UNEXPECTED;
                            throw;
                        }
                    }
				}
			}

            // Done with this handle
            CloseHandle(hThreadTok);
 		}
	}

	return hr;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CWMIManagement::ProcessPrivileges(TOKEN_PRIVILEGES *ptPriv, SAFEARRAY *& psaPrivNotHeld, SAFEARRAY * psaPrivReq )
{
	CAnsiUnicode XLate;
	BOOL fFound = FALSE;

	//==============================================================
	//  Create a temporary working array, we know the MAX can be
	//  the number of priv held + the number of priv req, so
	//  allocate it for that
	//==============================================================
	CSAFEARRAY PrivReq( psaPrivReq );
			

	long lMax = PrivReq.GetNumElements()+ptPriv->PrivilegeCount;
    psaPrivNotHeld = OMSSafeArrayCreate(VT_BSTR,lMax);	
	long nCurrentIndex = 0;

	//==============================================================
	// Get how many privs are not held
	//==============================================================
	for( long n = 0; n < PrivReq.GetNumElements(); n++ ){
		//==============================================================
		//  Now, get the privileges held array ready to put stuff in
		//==============================================================
		TCHAR * pPrivReq = NULL;
		CBSTR bstr;

        if( S_OK != PrivReq.Get(n, &bstr)){
			return;
		}
		fFound = FALSE;

#ifndef UNICODE
		XLate.UnicodeToAnsi(bstr,pPrivReq);
#else
		pPrivReq = (TCHAR *)bstr;
#endif
		// NTRaid:136384
		// 07/12/00
		if(pPrivReq)
		{

			for(int i=0;i < (int)ptPriv->PrivilegeCount;i++){
				DWORD dwPriv=128;
				TCHAR szPriv[NAME_SIZE*2];

				if( LookupPrivilegeName( NULL, &ptPriv->Privileges[i].Luid, szPriv, &dwPriv)){
						
					//==============================================
					//  If we found the privilege, then the user has
					//  it.  break out
					//==============================================
					if( _tcscmp( pPrivReq,pPrivReq ) == 0 ){
						fFound = TRUE;
						break;
					}

				}
				//==================================================
				//  If we didn't find it, then we need to add it to
				//  the list so we can notify the user
				//==================================================
				if( !fFound ){
					if( S_OK == SafeArrayPutElement(psaPrivNotHeld, &nCurrentIndex, bstr))
					{
    					nCurrentIndex++;
					}
				}
			}
		}
#ifndef UNICODE
        SAFE_DELETE_ARRAY(pPrivReq);
#else
		pPrivReq = NULL;
#endif
	}
	
	SAFEARRAYBOUND rgsabound[1];
   	rgsabound[0].lLbound = 0;
   	rgsabound[0].cElements = nCurrentIndex;
    HRESULT hr = SafeArrayRedim(psaPrivNotHeld, rgsabound);

	PrivReq.Unbind();
}