Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

700 lines
19 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows NT Security
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: defce.cpp
//
// Contents: Default Chain Engine Manager
//
// History: 21-Apr-98 kirtd Created
//
//----------------------------------------------------------------------------
#include <global.hxx>
//+---------------------------------------------------------------------------
//
// Member: CDefaultChainEngineMgr::CDefaultChainEngineMgr, public
//
// Synopsis: Constructor
//
//----------------------------------------------------------------------------
CDefaultChainEngineMgr::CDefaultChainEngineMgr ()
{
}
//+---------------------------------------------------------------------------
//
// Member: CDefaultChainEngineMgr::~CDefaultChainEngineMgr, public
//
// Synopsis: Destructor
//
//----------------------------------------------------------------------------
CDefaultChainEngineMgr::~CDefaultChainEngineMgr ()
{
}
//+---------------------------------------------------------------------------
//
// Member: CDefaultChainEngineMgr::Initialize, public
//
// Synopsis: initialization routine
//
//----------------------------------------------------------------------------
BOOL
CDefaultChainEngineMgr::Initialize ()
{
LRU_CACHE_CONFIG Config;
if (!Pki_InitializeCriticalSection( &m_Lock ))
{
return FALSE;
}
m_hLocalMachineEngine = NULL;
m_hProcessUserEngine = NULL;
m_hImpersonationCache = NULL;
memset( &Config, 0, sizeof( Config ) );
Config.dwFlags = LRU_CACHE_NO_SERIALIZE;
Config.cBuckets = DEFAULT_IMPERSONATION_CACHE_BUCKETS;
Config.MaxEntries = MAX_IMPERSONATION_CACHE_ENTRIES;
Config.pfnHash = DefaultChainEngineMgrHashTokenIdentifier;
Config.pfnOnRemoval = DefaultChainEngineMgrOnImpersonationEngineRemoval;
if (!I_CryptCreateLruCache( &Config, &m_hImpersonationCache ) )
{
DeleteCriticalSection( &m_Lock );
return FALSE;
}
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Member: CDefaultChainEngineMgr::Uninitialize, public
//
// Synopsis: uninitialization routine
//
//----------------------------------------------------------------------------
VOID
CDefaultChainEngineMgr::Uninitialize ()
{
if ( m_hLocalMachineEngine != NULL )
{
CertFreeCertificateChainEngine( m_hLocalMachineEngine );
}
if ( m_hProcessUserEngine != NULL )
{
CertFreeCertificateChainEngine( m_hProcessUserEngine );
}
if ( m_hImpersonationCache != NULL )
{
I_CryptFreeLruCache( m_hImpersonationCache, 0, NULL );
}
DeleteCriticalSection( &m_Lock );
}
//+---------------------------------------------------------------------------
//
// Member: CDefaultChainEngineMgr::GetDefaultEngine, public
//
// Synopsis: get the default engine
//
//----------------------------------------------------------------------------
BOOL
CDefaultChainEngineMgr::GetDefaultEngine (
IN HCERTCHAINENGINE hDefaultHandle,
OUT HCERTCHAINENGINE* phDefaultEngine
)
{
assert( ( hDefaultHandle == HCCE_LOCAL_MACHINE ) ||
( hDefaultHandle == HCCE_CURRENT_USER ) );
if ( hDefaultHandle == HCCE_LOCAL_MACHINE )
{
return( GetDefaultLocalMachineEngine( phDefaultEngine ) );
}
else if ( hDefaultHandle == HCCE_CURRENT_USER )
{
return( GetDefaultCurrentUserEngine( phDefaultEngine ) );
}
SetLastError( (DWORD) E_INVALIDARG );
return( FALSE );
}
//+---------------------------------------------------------------------------
//
// Member: CDefaultChainEngineMgr::GetDefaultLocalMachineEngine, public
//
// Synopsis: get the default local machine chain engine
//
//----------------------------------------------------------------------------
BOOL
CDefaultChainEngineMgr::GetDefaultLocalMachineEngine (
OUT HCERTCHAINENGINE* phDefaultEngine
)
{
BOOL fResult = TRUE;
EnterCriticalSection( &m_Lock );
if ( m_hLocalMachineEngine == NULL )
{
HCERTCHAINENGINE hEngine = NULL;
CERT_CHAIN_ENGINE_CONFIG Config;
LeaveCriticalSection( &m_Lock );
memset( &Config, 0, sizeof( Config ) );
Config.cbSize = sizeof( Config );
Config.dwFlags = CERT_CHAIN_USE_LOCAL_MACHINE_STORE;
Config.dwFlags |= CERT_CHAIN_ENABLE_CACHE_AUTO_UPDATE |
CERT_CHAIN_ENABLE_SHARE_STORE;
fResult = CertCreateCertificateChainEngine(
&Config,
&hEngine
);
EnterCriticalSection( &m_Lock );
if ( ( fResult == TRUE ) && ( m_hLocalMachineEngine == NULL ) )
{
m_hLocalMachineEngine = hEngine;
hEngine = NULL;
}
if ( hEngine != NULL )
{
( (PCCERTCHAINENGINE)hEngine )->Release();
}
}
if ( fResult == TRUE )
{
( (PCCERTCHAINENGINE)m_hLocalMachineEngine )->AddRef();
*phDefaultEngine = m_hLocalMachineEngine;
}
LeaveCriticalSection( &m_Lock );
return( fResult );
}
//+---------------------------------------------------------------------------
//
// Member: CDefaultChainEngineMgr::GetDefaultCurrentUserEngine, public
//
// Synopsis: get the default current user chain engine
//
//----------------------------------------------------------------------------
BOOL
CDefaultChainEngineMgr::GetDefaultCurrentUserEngine (
OUT HCERTCHAINENGINE* phDefaultEngine
)
{
BOOL fResult = TRUE;
HANDLE hUserToken;
EnterCriticalSection( &m_Lock );
if ( IsImpersonatingUser( &hUserToken ) == FALSE )
{
if ( GetLastError() != ERROR_NO_TOKEN )
{
LeaveCriticalSection( &m_Lock );
return( FALSE );
}
if ( m_hProcessUserEngine == NULL )
{
HCERTCHAINENGINE hEngine = NULL;
CERT_CHAIN_ENGINE_CONFIG Config;
LeaveCriticalSection( &m_Lock );
memset( &Config, 0, sizeof( Config ) );
Config.cbSize = sizeof( Config );
Config.dwFlags |= CERT_CHAIN_ENABLE_CACHE_AUTO_UPDATE |
CERT_CHAIN_ENABLE_SHARE_STORE;
fResult = CertCreateCertificateChainEngine(
&Config,
&hEngine
);
EnterCriticalSection( &m_Lock );
if ( ( fResult == TRUE ) && ( m_hProcessUserEngine == NULL ) )
{
m_hProcessUserEngine = hEngine;
hEngine = NULL;
}
if ( hEngine != NULL )
{
( (PCCERTCHAINENGINE)hEngine )->Release();
}
}
if ( fResult == TRUE )
{
( (PCCERTCHAINENGINE)m_hProcessUserEngine )->AddRef();
*phDefaultEngine = m_hProcessUserEngine;
}
}
else
{
fResult = GetDefaultCurrentImpersonatedUserEngine(
hUserToken,
phDefaultEngine
);
CloseHandle( hUserToken );
}
LeaveCriticalSection( &m_Lock );
return( fResult );
}
//+---------------------------------------------------------------------------
//
// Member: CDefaultChainEngineMgr::FlushDefaultEngine, public
//
// Synopsis: flush default engine
//
//----------------------------------------------------------------------------
VOID
CDefaultChainEngineMgr::FlushDefaultEngine (IN HCERTCHAINENGINE hDefaultHandle)
{
HCERTCHAINENGINE hEngine = NULL;
HLRUCACHE hCacheToFree = NULL;
HLRUCACHE hCache = NULL;
LRU_CACHE_CONFIG Config;
EnterCriticalSection( &m_Lock );
if ( hDefaultHandle == HCCE_CURRENT_USER )
{
hEngine = m_hProcessUserEngine;
m_hProcessUserEngine = NULL;
assert( m_hImpersonationCache != NULL );
memset( &Config, 0, sizeof( Config ) );
Config.dwFlags = LRU_CACHE_NO_SERIALIZE;
Config.cBuckets = DEFAULT_IMPERSONATION_CACHE_BUCKETS;
Config.MaxEntries = MAX_IMPERSONATION_CACHE_ENTRIES;
Config.pfnHash = DefaultChainEngineMgrHashTokenIdentifier;
Config.pfnOnRemoval = DefaultChainEngineMgrOnImpersonationEngineRemoval;
if ( I_CryptCreateLruCache( &Config, &hCache ) == TRUE )
{
hCacheToFree = m_hImpersonationCache;
m_hImpersonationCache = hCache;
}
else
{
I_CryptFlushLruCache( m_hImpersonationCache, 0, NULL );
}
assert( m_hImpersonationCache != NULL );
}
else if ( hDefaultHandle == HCCE_LOCAL_MACHINE )
{
hEngine = m_hLocalMachineEngine;
m_hLocalMachineEngine = NULL;
}
LeaveCriticalSection( &m_Lock );
if ( hEngine != NULL )
{
CertFreeCertificateChainEngine( hEngine );
}
if ( hCacheToFree != NULL )
{
I_CryptFreeLruCache( hCacheToFree, 0, NULL );
}
}
//+---------------------------------------------------------------------------
//
// Member: CDefaultChainEngineMgr::GetDefaultCurrentImpersonatedUserEngine
//
// Synopsis: get current impersonated user chain engine
//
//----------------------------------------------------------------------------
BOOL
CDefaultChainEngineMgr::GetDefaultCurrentImpersonatedUserEngine (
IN HANDLE hUserToken,
OUT HCERTCHAINENGINE* phDefaultEngine
)
{
BOOL fResult;
CRYPT_DATA_BLOB TokenId;
PCIMPERSONATIONENGINE pEngine = NULL;
HCERTCHAINENGINE hChainEngine = NULL;
fResult = GetTokenId( hUserToken, &TokenId );
if ( fResult == TRUE )
{
if ( FindImpersonationEngine( &TokenId, &pEngine ) == FALSE )
{
CERT_CHAIN_ENGINE_CONFIG Config;
LeaveCriticalSection( &m_Lock );
memset( &Config, 0, sizeof( Config ) );
Config.cbSize = sizeof( Config );
Config.dwFlags |= CERT_CHAIN_ENABLE_CACHE_AUTO_UPDATE |
CERT_CHAIN_ENABLE_SHARE_STORE;
fResult = CertCreateCertificateChainEngine(
&Config,
&hChainEngine
);
EnterCriticalSection( &m_Lock );
if ( fResult == TRUE )
{
fResult = FindImpersonationEngine( &TokenId, &pEngine );
if ( fResult == FALSE )
{
fResult = CreateImpersonationEngine(
&TokenId,
hChainEngine,
&pEngine
);
if ( fResult == TRUE )
{
hChainEngine = NULL;
AddToImpersonationCache( pEngine );
}
}
}
}
FreeTokenId( &TokenId );
}
if ( fResult == TRUE )
{
*phDefaultEngine = pEngine->ChainEngine();
( (PCCERTCHAINENGINE)*phDefaultEngine )->AddRef();
}
if ( pEngine != NULL )
{
pEngine->Release();
}
// NOTE: This release of the lock to free the unneeded chain engine handle
// must happen AFTER we're done with the impersonation engine and
// have addref'd the appropriate chain engine handle
if ( hChainEngine != NULL )
{
LeaveCriticalSection( &m_Lock );
CertFreeCertificateChainEngine( hChainEngine );
EnterCriticalSection( &m_Lock );
}
return( fResult );
}
//+---------------------------------------------------------------------------
//
// Member: CDefaultChainEngineMgr::IsImpersonatingUser, public
//
// Synopsis: is impersonating user?
//
//----------------------------------------------------------------------------
BOOL
CDefaultChainEngineMgr::IsImpersonatingUser (
OUT HANDLE* phUserToken
)
{
if ( FIsWinNT() == FALSE )
{
SetLastError( ERROR_NO_TOKEN );
return( FALSE );
}
return( OpenThreadToken(
GetCurrentThread(),
TOKEN_QUERY,
TRUE,
phUserToken
) );
}
//+---------------------------------------------------------------------------
//
// Member: CDefaultChainEngineMgr::GetTokenId, public
//
// Synopsis: get the token id which is the ModifiedId LUID inside of
// the TOKEN_STATISTICS information
//
//----------------------------------------------------------------------------
BOOL
CDefaultChainEngineMgr::GetTokenId (
IN HANDLE hUserToken,
OUT PCRYPT_DATA_BLOB pTokenId
)
{
BOOL fResult;
TOKEN_STATISTICS ts;
DWORD Length = 0;
fResult = GetTokenInformation(
hUserToken,
TokenStatistics,
&ts,
sizeof( ts ),
&Length
);
if ( fResult == TRUE )
{
pTokenId->cbData = sizeof( ts.ModifiedId );
pTokenId->pbData = new BYTE [ sizeof( ts.ModifiedId ) ];
if ( pTokenId->pbData != NULL )
{
memcpy(
pTokenId->pbData,
&ts.ModifiedId,
sizeof( ts.ModifiedId )
);
}
else
{
SetLastError( (DWORD) E_OUTOFMEMORY );
fResult = FALSE;
}
}
return( fResult );
}
//+---------------------------------------------------------------------------
//
// Member: CDefaultChainEngineMgr::FreeTokenId, public
//
// Synopsis: free token id
//
//----------------------------------------------------------------------------
VOID
CDefaultChainEngineMgr::FreeTokenId (
IN PCRYPT_DATA_BLOB pTokenId
)
{
delete pTokenId->pbData;
}
//+---------------------------------------------------------------------------
//
// Member: CDefaultChainEngineMgr::FindImpersonationEngine, public
//
// Synopsis: find the impersonation engine
//
//----------------------------------------------------------------------------
BOOL
CDefaultChainEngineMgr::FindImpersonationEngine (
IN PCRYPT_DATA_BLOB pTokenId,
OUT PCIMPERSONATIONENGINE* ppEngine
)
{
HLRUENTRY hFound;
PCIMPERSONATIONENGINE pEngine = NULL;
hFound = I_CryptFindLruEntry( m_hImpersonationCache, pTokenId );
if ( hFound != NULL )
{
pEngine = (PCIMPERSONATIONENGINE)I_CryptGetLruEntryData( hFound );
pEngine->AddRef();
*ppEngine = pEngine;
I_CryptReleaseLruEntry( hFound );
return( TRUE );
}
return( FALSE );
}
//+---------------------------------------------------------------------------
//
// Member: CDefaultChainEngineMgr::CreateImpersonationEngine, public
//
// Synopsis: create an impersonation engine
//
//----------------------------------------------------------------------------
BOOL
CDefaultChainEngineMgr::CreateImpersonationEngine (
IN PCRYPT_DATA_BLOB pTokenId,
IN HCERTCHAINENGINE hChainEngine,
OUT PCIMPERSONATIONENGINE* ppEngine
)
{
BOOL fResult = FALSE;
PCIMPERSONATIONENGINE pEngine;
pEngine = new CImpersonationEngine(
m_hImpersonationCache,
hChainEngine,
pTokenId,
fResult
);
if ( pEngine == NULL )
{
SetLastError( (DWORD) E_OUTOFMEMORY );
return( FALSE );
}
else if ( fResult == FALSE )
{
delete pEngine;
return( FALSE );
}
*ppEngine = pEngine;
return( TRUE );
}
//+---------------------------------------------------------------------------
//
// Member: CDefaultChainEngineMgr::AddToImpersonationCache, public
//
// Synopsis: add to the cache
//
//----------------------------------------------------------------------------
VOID
CDefaultChainEngineMgr::AddToImpersonationCache(
IN PCIMPERSONATIONENGINE pEngine
)
{
pEngine->AddRef();
I_CryptInsertLruEntry( pEngine->LruEntry(), NULL );
}
//+---------------------------------------------------------------------------
//
// Function: DefaultChainEngineMgrOnImpersonationEngineRemoval
//
// Synopsis: removal notification
//
//----------------------------------------------------------------------------
VOID WINAPI
DefaultChainEngineMgrOnImpersonationEngineRemoval (
IN LPVOID pv,
IN LPVOID pvRemovalContext
)
{
( (PCIMPERSONATIONENGINE)pv )->Release();
}
//+---------------------------------------------------------------------------
//
// Function: DefaultChainEngineMgrHashTokenIdentifier
//
// Synopsis: hash the token identifier
//
//----------------------------------------------------------------------------
DWORD WINAPI
DefaultChainEngineMgrHashTokenIdentifier (
IN PCRYPT_DATA_BLOB pIdentifier
)
{
DWORD dwHash = 0;
DWORD cb = pIdentifier->cbData;
LPBYTE pb = pIdentifier->pbData;
while ( cb-- )
{
if ( dwHash & 0x80000000 )
{
dwHash = ( dwHash << 1 ) | 1;
}
else
{
dwHash = dwHash << 1;
}
dwHash += *pb++;
}
return( dwHash );
}
//+---------------------------------------------------------------------------
//
// Member: CImpersonationEngine::CImpersonationEngine, public
//
// Synopsis: Constructor
//
//----------------------------------------------------------------------------
CImpersonationEngine::CImpersonationEngine (
IN HLRUCACHE hCache,
IN HCERTCHAINENGINE hChainEngine,
IN PCRYPT_DATA_BLOB pTokenId,
OUT BOOL& rfResult
)
{
m_cRefs = 1;
m_hChainEngine = NULL;
m_hLruEntry = NULL;
rfResult = I_CryptCreateLruEntry(
hCache,
pTokenId,
this,
&m_hLruEntry
);
if ( rfResult == TRUE )
{
m_hChainEngine = hChainEngine;
}
}
//+---------------------------------------------------------------------------
//
// Member: CImpersonationEngine::~CImpersonationEngine, public
//
// Synopsis: Destructor
//
//----------------------------------------------------------------------------
CImpersonationEngine::~CImpersonationEngine ()
{
if ( m_hLruEntry != NULL )
{
I_CryptReleaseLruEntry( m_hLruEntry );
}
if ( m_hChainEngine != NULL )
{
CertFreeCertificateChainEngine( m_hChainEngine );
}
}