//+--------------------------------------------------------------------------- // // 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 //+--------------------------------------------------------------------------- // // 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 ); } }