1003 lines
24 KiB
C++
1003 lines
24 KiB
C++
/*++
|
|
|
|
Copyright (C) 1998-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
CALLSEC.CPP
|
|
|
|
Abstract:
|
|
|
|
IWbemCallSecurity, IServerSecurity implementation for
|
|
provider impersonation.
|
|
|
|
History:
|
|
|
|
raymcc 29-Jul-98 First draft.
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include <stdio.h>
|
|
|
|
#include <initguid.h>
|
|
#include <winntsec.h>
|
|
#include <callsec.h>
|
|
#include <cominit.h>
|
|
#include <arrtempl.h>
|
|
#include <cominit.h>
|
|
#include <genutils.h>
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CWbemCallSecurity
|
|
//
|
|
// This object is used to supply client impersonation to providers.
|
|
//
|
|
// Usage:
|
|
// (1) When client first makes call, call CreateInst() and get a new
|
|
// empty object (ref count of 1). Constructors/Destructors are private.
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
|
|
CWbemCallSecurity::CWbemCallSecurity()
|
|
{
|
|
OSVERSIONINFO os;
|
|
os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
GetVersionEx(&os);
|
|
if (os.dwPlatformId != VER_PLATFORM_WIN32_NT)
|
|
m_bWin9x = TRUE;
|
|
else
|
|
m_bWin9x = FALSE;
|
|
|
|
m_lRef = 1; // Ref count
|
|
|
|
m_hThreadToken = 0; // Handle to thread imp token
|
|
|
|
m_dwPotentialImpLevel = 0; // Potential
|
|
m_dwActiveImpLevel = 0; // Active impersonation
|
|
|
|
m_dwAuthnSvc = 0;
|
|
m_dwAuthzSvc = 0;
|
|
m_dwAuthnLevel = 0;
|
|
|
|
m_pServerPrincNam = 0;
|
|
m_pIdentity = 0;
|
|
}
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// ~CWbemCallSecurity
|
|
//
|
|
// Destructor. Closes any open handles, deallocates any non-NULL
|
|
// strings.
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
|
|
CWbemCallSecurity::~CWbemCallSecurity()
|
|
{
|
|
if (m_hThreadToken)
|
|
CloseHandle(m_hThreadToken);
|
|
|
|
if (m_pServerPrincNam)
|
|
CoTaskMemFree(m_pServerPrincNam);
|
|
|
|
if (m_pIdentity)
|
|
CoTaskMemFree(m_pIdentity);
|
|
}
|
|
|
|
void
|
|
CWbemCallSecurity::operator=(const CWbemCallSecurity& Other)
|
|
{
|
|
if(m_hThreadToken)
|
|
{
|
|
CloseHandle(m_hThreadToken);
|
|
m_hThreadToken=NULL ;
|
|
}
|
|
|
|
if ( Other.m_hThreadToken )
|
|
{
|
|
DuplicateHandle(
|
|
GetCurrentProcess(),
|
|
Other.m_hThreadToken,
|
|
GetCurrentProcess(),
|
|
&m_hThreadToken,
|
|
0,
|
|
TRUE,
|
|
DUPLICATE_SAME_ACCESS);
|
|
}
|
|
|
|
m_dwPotentialImpLevel = Other.m_dwPotentialImpLevel;
|
|
m_dwActiveImpLevel = 0;
|
|
|
|
m_dwAuthnSvc = Other.m_dwAuthnSvc;
|
|
m_dwAuthzSvc = Other.m_dwAuthzSvc;
|
|
m_dwAuthnLevel = Other.m_dwAuthnLevel;
|
|
|
|
if(m_pServerPrincNam)
|
|
{
|
|
CoTaskMemFree(m_pServerPrincNam);
|
|
m_pServerPrincNam = NULL;
|
|
}
|
|
|
|
if (Other.m_pServerPrincNam)
|
|
{
|
|
m_pServerPrincNam = (LPWSTR)CoTaskMemAlloc(
|
|
(wcslen(Other.m_pServerPrincNam) + 1) * 2);
|
|
if(m_pServerPrincNam)
|
|
wcscpy(m_pServerPrincNam, Other.m_pServerPrincNam);
|
|
}
|
|
|
|
if(m_pIdentity)
|
|
{
|
|
CoTaskMemFree(m_pIdentity);
|
|
m_pIdentity = NULL;
|
|
}
|
|
|
|
if (Other.m_pIdentity)
|
|
{
|
|
m_pIdentity = (LPWSTR)CoTaskMemAlloc(
|
|
(wcslen(Other.m_pIdentity) + 1) * 2);
|
|
if(m_pIdentity)
|
|
wcscpy(m_pIdentity, Other.m_pIdentity);
|
|
}
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CWbemCallSecurity::AddRef
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
|
|
ULONG CWbemCallSecurity::AddRef()
|
|
{
|
|
return InterlockedIncrement(&m_lRef);
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CWbemCallSecurity::Release
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
|
|
ULONG CWbemCallSecurity::Release()
|
|
{
|
|
long lRef = InterlockedDecrement(&m_lRef);
|
|
if(lRef == 0)
|
|
delete this;
|
|
return lRef;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CWbemCallSecurity::QueryInterface
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
|
|
HRESULT CWbemCallSecurity::QueryInterface(REFIID riid, void** ppv)
|
|
{
|
|
if(riid == IID_IUnknown)
|
|
{
|
|
*ppv = (IUnknown *) this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
else if (riid == IID_IServerSecurity)
|
|
{
|
|
*ppv = (IServerSecurity *) this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
else if (riid == IID_IWbemCallSecurity)
|
|
{
|
|
*ppv = (IWbemCallSecurity *) this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
else return E_NOINTERFACE;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CWbemCallSecurity:QueryBlanket
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
|
|
HRESULT STDMETHODCALLTYPE CWbemCallSecurity::QueryBlanket(
|
|
/* [out] */ DWORD __RPC_FAR *pAuthnSvc,
|
|
/* [out] */ DWORD __RPC_FAR *pAuthzSvc,
|
|
/* [out] */ OLECHAR __RPC_FAR *__RPC_FAR *pServerPrincName,
|
|
/* [out] */ DWORD __RPC_FAR *pAuthnLevel,
|
|
/* [out] */ DWORD __RPC_FAR *pImpLevel,
|
|
/* [out] */ void __RPC_FAR *__RPC_FAR *pPrivs,
|
|
/* [out] */ DWORD __RPC_FAR *pCapabilities
|
|
)
|
|
{
|
|
if (m_bWin9x)
|
|
return E_NOTIMPL;
|
|
|
|
if (m_dwPotentialImpLevel == 0 )
|
|
return E_FAIL;
|
|
|
|
// Return DWORD parameters, after checking.
|
|
// ========================================
|
|
|
|
if (pAuthnSvc)
|
|
*pAuthnSvc = m_dwAuthnSvc;
|
|
|
|
if (pAuthzSvc)
|
|
*pAuthzSvc = m_dwAuthzSvc ;
|
|
|
|
if (pImpLevel)
|
|
*pImpLevel = m_dwActiveImpLevel ;
|
|
|
|
if (pAuthnLevel)
|
|
*pAuthnLevel = m_dwAuthnLevel;
|
|
|
|
if (pServerPrincName)
|
|
{
|
|
*pServerPrincName = 0;
|
|
|
|
if (m_pServerPrincNam)
|
|
{
|
|
*pServerPrincName = (LPWSTR) CoTaskMemAlloc((wcslen(m_pServerPrincNam) + 1) * 2);
|
|
wcscpy(*pServerPrincName, m_pServerPrincNam);
|
|
}
|
|
}
|
|
|
|
if (pPrivs)
|
|
{
|
|
*pPrivs = m_pIdentity; // Documented to point to an internal!!
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CWbemCallSecurity::ImpersonateClient
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
|
|
HRESULT STDMETHODCALLTYPE CWbemCallSecurity::ImpersonateClient(void)
|
|
{
|
|
if (m_bWin9x)
|
|
return E_NOTIMPL;
|
|
|
|
if (m_dwActiveImpLevel != 0) // Already impersonating
|
|
return S_OK;
|
|
|
|
if(m_hThreadToken == NULL)
|
|
{
|
|
return WBEM_E_INVALID_CONTEXT;
|
|
}
|
|
|
|
if (m_dwPotentialImpLevel == 0)
|
|
return (ERROR_CANT_OPEN_ANONYMOUS | 0x80070000);
|
|
|
|
BOOL bRes;
|
|
|
|
bRes = SetThreadToken(NULL, m_hThreadToken);
|
|
|
|
if (bRes)
|
|
{
|
|
m_dwActiveImpLevel = m_dwPotentialImpLevel;
|
|
return S_OK;
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CWbemCallSecurity::RevertToSelf
|
|
//
|
|
// Returns S_OK or E_FAIL.
|
|
// Returns E_NOTIMPL on Win9x platforms.
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
|
|
HRESULT STDMETHODCALLTYPE CWbemCallSecurity::RevertToSelf( void)
|
|
{
|
|
if (m_bWin9x)
|
|
return E_NOTIMPL;
|
|
|
|
if (m_dwActiveImpLevel == 0)
|
|
return S_OK;
|
|
|
|
if (m_dwPotentialImpLevel == 0)
|
|
return (ERROR_CANT_OPEN_ANONYMOUS | 0x80070000);
|
|
|
|
// If here,we are impersonating and can definitely revert.
|
|
// =======================================================
|
|
|
|
BOOL bRes = SetThreadToken(NULL, NULL);
|
|
|
|
if (bRes == FALSE)
|
|
return E_FAIL;
|
|
|
|
m_dwActiveImpLevel = 0; // No longer actively impersonating
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CWbemCallSecurity::IsImpersonating
|
|
//
|
|
//***************************************************************************
|
|
|
|
BOOL STDMETHODCALLTYPE CWbemCallSecurity::IsImpersonating( void)
|
|
{
|
|
if (m_hThreadToken && m_dwActiveImpLevel != 0)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CWbemCallSecurity::CreateInst
|
|
//
|
|
// Creates a new instance
|
|
//***************************************************************************
|
|
// ok
|
|
|
|
IWbemCallSecurity * CWbemCallSecurity::CreateInst()
|
|
{
|
|
return (IWbemCallSecurity *) new CWbemCallSecurity; // Constructed with ref count of 1
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CWbemCallSecurity::GetPotentialImpersonation
|
|
//
|
|
// Returns 0 if no impersonation is currently possible or the
|
|
// level which would be active during impersonation:
|
|
//
|
|
// RPC_C_IMP_LEVEL_ANONYMOUS
|
|
// RPC_C_IMP_LEVEL_IDENTIFY
|
|
// RPC_C_IMP_LEVEL_IMPERSONATE
|
|
// RPC_C_IMP_LEVEL_DELEGATE
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
|
|
HRESULT CWbemCallSecurity::GetPotentialImpersonation()
|
|
{
|
|
return m_dwPotentialImpLevel;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CWbemCallSecurity::GetActiveImpersonation
|
|
//
|
|
// Returns 0 if no impersonation is currently active or the
|
|
// currently active level:
|
|
//
|
|
// RPC_C_IMP_LEVEL_ANONYMOUS
|
|
// RPC_C_IMP_LEVEL_IDENTIFY
|
|
// RPC_C_IMP_LEVEL_IMPERSONATE
|
|
// RPC_C_IMP_LEVEL_DELEGATE
|
|
//
|
|
//***************************************************************************
|
|
// ok
|
|
|
|
HRESULT CWbemCallSecurity::GetActiveImpersonation()
|
|
{
|
|
return m_dwActiveImpLevel;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
// CWbemCallSecurity::CloneThreadContext
|
|
//
|
|
// Call this on a thread to retrieve the potential impersonation info for
|
|
// that thread and set the current object to be able to duplicate it later.
|
|
//
|
|
// Return codes:
|
|
//
|
|
// S_OK
|
|
// E_FAIL
|
|
// E_NOTIMPL on Win9x
|
|
// E_ABORT if the calling thread is already impersonating a client.
|
|
//
|
|
//***************************************************************************
|
|
|
|
HRESULT CWbemCallSecurity::CloneThreadContext(BOOL bInternallyIssued)
|
|
{
|
|
|
|
// If on Win9x, don't bother.
|
|
// ==========================
|
|
|
|
if (m_bWin9x)
|
|
return E_NOTIMPL;
|
|
|
|
if (m_hThreadToken) // Already called this
|
|
return E_ABORT;
|
|
|
|
// Get the current context.
|
|
// ========================
|
|
|
|
IServerSecurity *pSec = 0;
|
|
HRESULT hRes = WbemCoGetCallContext(IID_IServerSecurity, (LPVOID *) &pSec);
|
|
CReleaseMe rmSec(pSec);
|
|
|
|
if (hRes != S_OK)
|
|
{
|
|
// There is no call context --- this must be an in-proc object calling
|
|
// us from its own thread. Initialize from current thread token
|
|
// ===================================================================
|
|
|
|
return CloneThreadToken();
|
|
}
|
|
|
|
// Figure out if the call context is ours or RPCs
|
|
// ==============================================
|
|
|
|
IWbemCallSecurity* pInternal = NULL;
|
|
if(SUCCEEDED(pSec->QueryInterface(IID_IWbemCallSecurity,
|
|
(void**)&pInternal)))
|
|
{
|
|
CReleaseMe rmInt(pInternal);
|
|
// This is our own call context --- this must be ab in-proc object
|
|
// calling us from our thread. Behave depending on the flags
|
|
// ===============================================================
|
|
if(bInternallyIssued)
|
|
{
|
|
// Internal requests always propagate context. Therefore, we just
|
|
// copy the context that we have got
|
|
// ==============================================================
|
|
|
|
*this = *(CWbemCallSecurity*)pInternal;
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
// Provider request --- Initialize from the current thread token
|
|
// =============================================================
|
|
return CloneThreadToken();
|
|
}
|
|
}
|
|
|
|
// If here, we are not impersonating and we want to gather info
|
|
// about the client's call.
|
|
// ============================================================
|
|
|
|
RPC_AUTHZ_HANDLE hAuth;
|
|
|
|
// Ensures auto release of the mutex if we crash
|
|
CAutoSecurityMutex autosm;
|
|
|
|
DWORD t_ImpLevel = 0 ;
|
|
|
|
hRes = pSec->QueryBlanket(
|
|
&m_dwAuthnSvc,
|
|
&m_dwAuthzSvc,
|
|
&m_pServerPrincNam,
|
|
&m_dwAuthnLevel,
|
|
&t_ImpLevel,
|
|
&hAuth, // RPC_AUTHZ_HANDLE
|
|
NULL // Capabilities; not used
|
|
);
|
|
|
|
if(FAILED(hRes))
|
|
{
|
|
|
|
// In some cases, we cant get the name, but the rest is ok. In particular
|
|
// the temporary SMS accounts have that property. Or nt 4 after IPCONFIG /RELEASE
|
|
|
|
hRes = pSec->QueryBlanket(
|
|
&m_dwAuthnSvc,
|
|
&m_dwAuthzSvc,
|
|
&m_pServerPrincNam,
|
|
&m_dwAuthnLevel,
|
|
&t_ImpLevel,
|
|
NULL, // RPC_AUTHZ_HANDLE
|
|
NULL // Capabilities; not used
|
|
);
|
|
hAuth = NULL;
|
|
}
|
|
|
|
// We don't need this anymore.
|
|
autosm.Release();
|
|
|
|
if(FAILED(hRes))
|
|
{
|
|
// THIS IS A WORKAROUND FOR COM BUG:
|
|
// This failure is indicative of an anonymous-level client.
|
|
// ========================================================
|
|
|
|
m_dwPotentialImpLevel = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
if (hAuth)
|
|
{
|
|
m_pIdentity = LPWSTR(CoTaskMemAlloc((wcslen(LPWSTR(hAuth)) + 1) * 2));
|
|
if(m_pIdentity)
|
|
wcscpy(m_pIdentity, LPWSTR(hAuth));
|
|
}
|
|
|
|
// Impersonate the client long enough to clone the thread token.
|
|
// =============================================================
|
|
|
|
BOOL bImp = pSec->IsImpersonating();
|
|
if(!bImp)
|
|
hRes = pSec->ImpersonateClient();
|
|
|
|
if (FAILED(hRes))
|
|
{
|
|
if(!bImp)
|
|
pSec->RevertToSelf();
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT hres = CloneThreadToken();
|
|
|
|
if(!bImp)
|
|
pSec->RevertToSelf();
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT CWbemCallSecurity::CloneThreadToken()
|
|
{
|
|
HANDLE hPrimary = 0 ;
|
|
HANDLE hToken = 0;
|
|
|
|
BOOL bRes = OpenThreadToken(
|
|
GetCurrentThread(),
|
|
TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE,
|
|
TRUE,
|
|
&hToken
|
|
);
|
|
|
|
if (bRes == FALSE)
|
|
{
|
|
m_hThreadToken = NULL;
|
|
m_dwAuthnSvc = RPC_C_AUTHN_WINNT;
|
|
m_dwAuthzSvc = RPC_C_AUTHZ_NONE;
|
|
m_dwAuthnLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
|
|
m_pServerPrincNam = NULL;
|
|
m_pIdentity = NULL;
|
|
|
|
long lRes = GetLastError();
|
|
if(lRes == ERROR_NO_IMPERSONATION_TOKEN || lRes == ERROR_NO_TOKEN)
|
|
{
|
|
// This is the basic process thread.
|
|
// =================================
|
|
|
|
bRes = OpenProcessToken(
|
|
|
|
GetCurrentProcess(),
|
|
TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE,
|
|
&hPrimary
|
|
);
|
|
|
|
if (bRes==FALSE)
|
|
{
|
|
// Unknown error
|
|
// =============
|
|
m_dwPotentialImpLevel = 0;
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
else if(lRes == ERROR_CANT_OPEN_ANONYMOUS)
|
|
{
|
|
// Anonymous call
|
|
// ==============
|
|
|
|
m_dwPotentialImpLevel = 0;
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
// Unknown error
|
|
// =============
|
|
|
|
m_dwPotentialImpLevel = 0;
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
|
|
// Find out token info.
|
|
// =====================
|
|
|
|
SECURITY_IMPERSONATION_LEVEL t_Level = SecurityImpersonation ;
|
|
|
|
if ( hToken )
|
|
{
|
|
DWORD dwBytesReturned = 0;
|
|
|
|
bRes = GetTokenInformation (
|
|
|
|
hToken,
|
|
TokenImpersonationLevel,
|
|
( void * ) & t_Level,
|
|
sizeof ( t_Level ),
|
|
&dwBytesReturned
|
|
);
|
|
|
|
if (bRes == FALSE)
|
|
{
|
|
CloseHandle(hToken);
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
switch (t_Level)
|
|
{
|
|
case SecurityAnonymous:
|
|
m_dwPotentialImpLevel = RPC_C_IMP_LEVEL_ANONYMOUS;
|
|
break;
|
|
|
|
case SecurityIdentification:
|
|
m_dwPotentialImpLevel = RPC_C_IMP_LEVEL_IDENTIFY;
|
|
break;
|
|
|
|
case SecurityImpersonation:
|
|
m_dwPotentialImpLevel = RPC_C_IMP_LEVEL_IMPERSONATE;
|
|
break;
|
|
|
|
case SecurityDelegation:
|
|
m_dwPotentialImpLevel = RPC_C_IMP_LEVEL_DELEGATE;
|
|
break;
|
|
|
|
default:
|
|
m_dwPotentialImpLevel = 0;
|
|
break;
|
|
}
|
|
|
|
// Duplicate the handle.
|
|
// ============================
|
|
|
|
bRes = DuplicateToken (
|
|
hToken ? hToken : hPrimary ,
|
|
(SECURITY_IMPERSONATION_LEVEL)t_Level,
|
|
&m_hThreadToken
|
|
);
|
|
|
|
if ( hToken )
|
|
{
|
|
CloseHandle(hToken);
|
|
}
|
|
else
|
|
{
|
|
CloseHandle(hPrimary);
|
|
}
|
|
|
|
if (bRes == FALSE)
|
|
return E_FAIL;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
RELEASE_ME CWbemCallSecurity* CWbemCallSecurity::MakeInternalCopyOfThread()
|
|
{
|
|
IServerSecurity* pSec;
|
|
HRESULT hres = WbemCoGetCallContext(IID_IServerSecurity, (void**)&pSec);
|
|
if(FAILED(hres))
|
|
return NULL;
|
|
|
|
CReleaseMe rm1(pSec);
|
|
|
|
IServerSecurity* pIntSec;
|
|
hres = pSec->QueryInterface(IID_IWbemCallSecurity, (void**)&pIntSec);
|
|
if(FAILED(hres))
|
|
return NULL;
|
|
|
|
CWbemCallSecurity* pCopy = new CWbemCallSecurity;
|
|
|
|
if (pCopy)
|
|
*pCopy = *(CWbemCallSecurity*)pIntSec;
|
|
|
|
pIntSec->Release();
|
|
return pCopy;
|
|
}
|
|
|
|
|
|
DWORD CWbemCallSecurity::GetAuthenticationId(LUID& rluid)
|
|
{
|
|
if(m_hThreadToken == NULL)
|
|
return ERROR_INVALID_HANDLE;
|
|
|
|
TOKEN_STATISTICS stat;
|
|
DWORD dwRet;
|
|
if(!GetTokenInformation(m_hThreadToken, TokenStatistics,
|
|
(void*)&stat, sizeof(stat), &dwRet))
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
rluid = stat.AuthenticationId;
|
|
return 0;
|
|
}
|
|
|
|
HANDLE CWbemCallSecurity::GetToken()
|
|
{
|
|
return m_hThreadToken;
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
|
|
void CWbemCallSecurity::DumpCurrentContext()
|
|
{
|
|
if (m_bWin9x)
|
|
return;
|
|
|
|
HANDLE hThreadToken;
|
|
|
|
BOOL bRes = OpenThreadToken(
|
|
GetCurrentThread(),
|
|
TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE,
|
|
TRUE,
|
|
&hThreadToken
|
|
);
|
|
|
|
if (!bRes)
|
|
return;
|
|
|
|
const DWORD dwBytes = 512;
|
|
BYTE Buf[dwBytes], Name[dwBytes], Domain[dwBytes];
|
|
DWORD dwBytesReturned = 0, dwDomainSize = dwBytes, dwNameSize = dwBytes;
|
|
|
|
GetTokenInformation(hThreadToken, TokenUser, Buf, dwBytes, &dwBytesReturned);
|
|
|
|
SID_NAME_USE snu;
|
|
|
|
SetThreadToken(NULL, NULL);
|
|
|
|
bRes = LookupAccountSidW(NULL, ((PTOKEN_USER) Buf)->User.Sid, LPWSTR(Name), &dwNameSize,
|
|
LPWSTR(Domain), &dwDomainSize, &snu);
|
|
|
|
SetThreadToken(NULL, hThreadToken);
|
|
|
|
printf("User = %S\\%S\n", Domain, Name);
|
|
|
|
CloseHandle(hThreadToken);
|
|
}
|
|
|
|
|
|
|
|
CDerivedObjectSecurity::CDerivedObjectSecurity()
|
|
{
|
|
m_bValid = FALSE;
|
|
m_bEnabled = TRUE;
|
|
|
|
if(!IsNT() || !IsDcomEnabled())
|
|
{
|
|
m_bEnabled = FALSE;
|
|
m_bValid = TRUE;
|
|
}
|
|
|
|
HRESULT hres = RetrieveSidFromCall(&m_sidUser);
|
|
if(FAILED(hres))
|
|
return;
|
|
|
|
// Revert to self while remebering the thread token
|
|
// ================================================
|
|
|
|
BOOL bRes;
|
|
HANDLE hThreadToken = NULL;
|
|
bRes = OpenThreadToken(GetCurrentThread(), TOKEN_READ | TOKEN_IMPERSONATE,
|
|
TRUE, &hThreadToken);
|
|
|
|
if(bRes)
|
|
SetThreadToken(NULL, NULL);
|
|
|
|
// Open process token
|
|
// ==================
|
|
|
|
HANDLE hProcessToken;
|
|
bRes = OpenProcessToken(GetCurrentProcess(), TOKEN_READ,
|
|
&hProcessToken);
|
|
if(!bRes)
|
|
{
|
|
if(hThreadToken)
|
|
CloseHandle(hThreadToken);
|
|
return;
|
|
}
|
|
|
|
// Retrieve our process SID
|
|
// ========================
|
|
|
|
hres = RetrieveSidFromToken(hProcessToken, &m_sidSystem);
|
|
CloseHandle(hProcessToken);
|
|
|
|
// Re-impersonate the original thread token
|
|
// ========================================
|
|
|
|
if(hThreadToken)
|
|
{
|
|
SetThreadToken(NULL, hThreadToken);
|
|
CloseHandle(hThreadToken);
|
|
}
|
|
|
|
|
|
if(FAILED(hres))
|
|
return;
|
|
|
|
m_bValid = TRUE;
|
|
}
|
|
|
|
HRESULT CDerivedObjectSecurity::RetrieveSidFromCall(CNtSid* psid)
|
|
{
|
|
HANDLE hToken;
|
|
HRESULT hres;
|
|
BOOL bRes;
|
|
|
|
// Check if we are on an impersonated thread
|
|
// =========================================
|
|
|
|
bRes = OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &hToken);
|
|
if(bRes)
|
|
{
|
|
// We are --- just use this token for authentication
|
|
// =================================================
|
|
hres = RetrieveSidFromToken(hToken, psid);
|
|
CloseHandle(hToken);
|
|
return hres;
|
|
}
|
|
|
|
// Construct CWbemCallSecurity that will determine (according to our
|
|
// non-trivial provider handling rules) the security context of this
|
|
// call
|
|
// =================================================================
|
|
|
|
IWbemCallSecurity* pServerSec = CWbemCallSecurity::CreateInst();
|
|
if(pServerSec == NULL)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
|
|
CReleaseMe rm1(pServerSec);
|
|
|
|
hres = pServerSec->CloneThreadContext(FALSE);
|
|
if(FAILED(hres))
|
|
return hres;
|
|
|
|
// Impersonate client
|
|
// ==================
|
|
|
|
hres = pServerSec->ImpersonateClient();
|
|
if(FAILED(hres))
|
|
return hres;
|
|
|
|
// Open impersonated token
|
|
// =======================
|
|
|
|
bRes = OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &hToken);
|
|
if(!bRes)
|
|
{
|
|
long lRes = GetLastError();
|
|
if(lRes == ERROR_NO_IMPERSONATION_TOKEN || lRes == ERROR_NO_TOKEN)
|
|
{
|
|
// Not impersonating --- get the process token instead
|
|
// ===================================================
|
|
|
|
bRes = OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken);
|
|
if(!bRes)
|
|
{
|
|
pServerSec->RevertToSelf();
|
|
return WBEM_E_ACCESS_DENIED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Real problems
|
|
// =============
|
|
pServerSec->RevertToSelf();
|
|
return WBEM_E_ACCESS_DENIED;
|
|
}
|
|
}
|
|
|
|
hres = RetrieveSidFromToken(hToken, psid);
|
|
CloseHandle(hToken);
|
|
pServerSec->RevertToSelf();
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CDerivedObjectSecurity::RetrieveSidFromToken(HANDLE hToken,
|
|
CNtSid* psid)
|
|
{
|
|
// Retrieve the length of the user sid structure
|
|
// =============================================
|
|
|
|
BOOL bRes;
|
|
|
|
DWORD dwLen = 0;
|
|
TOKEN_USER tu;
|
|
memset(&tu,0,sizeof(TOKEN_USER));
|
|
bRes = GetTokenInformation(hToken, TokenUser, &tu, sizeof(TOKEN_USER), &dwLen);
|
|
DWORD dwLast = GetLastError();
|
|
if(bRes)
|
|
{
|
|
// 1-length sid? I don't think so
|
|
return WBEM_E_CRITICAL_ERROR;
|
|
}
|
|
|
|
// Allocate buffer to hold user sid
|
|
// ================================
|
|
|
|
BYTE* pBuffer = new BYTE[dwLen];
|
|
if(pBuffer == NULL)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
|
|
CVectorDeleteMe<BYTE> dm1(pBuffer);
|
|
|
|
// Retrieve the user sid structure
|
|
// ===============================
|
|
|
|
bRes = GetTokenInformation(hToken, TokenUser, pBuffer, dwLen, &dwLen);
|
|
|
|
if(!bRes)
|
|
return WBEM_E_ACCESS_DENIED;
|
|
|
|
TOKEN_USER* pUser = (TOKEN_USER*)pBuffer;
|
|
|
|
// Set our sid to the returned one
|
|
// ===============================
|
|
|
|
*psid = CNtSid(pUser->User.Sid);
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
|
|
|
|
|
|
CDerivedObjectSecurity::~CDerivedObjectSecurity()
|
|
{
|
|
}
|
|
|
|
BOOL CDerivedObjectSecurity::AccessCheck()
|
|
{
|
|
if(!m_bValid)
|
|
return FALSE;
|
|
|
|
if(!m_bEnabled)
|
|
return TRUE;
|
|
|
|
// Find out who is calling
|
|
// =======================
|
|
|
|
CNtSid sidCaller;
|
|
HRESULT hres = RetrieveSidFromCall(&sidCaller);
|
|
if(FAILED(hres))
|
|
return FALSE;
|
|
|
|
// Compare the caller to the issuing user and ourselves
|
|
// ====================================================
|
|
|
|
if(sidCaller == m_sidUser || sidCaller == m_sidSystem)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|