|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows NT Security
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: orm.cpp
//
// Contents: Implementation of object retrieval manager
//
// History: 24-Jul-97 kirtd Created
// 01-Jan-02 philh Changed to internally use UNICODE Urls
//
//----------------------------------------------------------------------------
#include <global.hxx>
#ifndef INTERNET_MAX_SCHEME_LENGTH
#define INTERNET_MAX_SCHEME_LENGTH 32 // longest protocol name length
#endif
//+---------------------------------------------------------------------------
//
// Member: CObjectRetrievalManager::CObjectRetrievalManager, public
//
// Synopsis: Constructor
//
//----------------------------------------------------------------------------
CObjectRetrievalManager::CObjectRetrievalManager () { m_cRefs = 1; m_hSchemeRetrieve = NULL; m_pfnSchemeRetrieve = NULL; m_hContextCreate = NULL; m_pfnContextCreate = NULL; }
//+---------------------------------------------------------------------------
//
// Member: CObjectRetrievalManager::~CObjectRetrievalManager, public
//
// Synopsis: Destructor
//
//----------------------------------------------------------------------------
CObjectRetrievalManager::~CObjectRetrievalManager () { }
//+---------------------------------------------------------------------------
//
// Member: CObjectRetrievalManager::AddRef, public
//
// Synopsis: IRefCountedObject::AddRef
//
//----------------------------------------------------------------------------
VOID CObjectRetrievalManager::AddRef () { InterlockedIncrement( (LONG *)&m_cRefs ); }
//+---------------------------------------------------------------------------
//
// Member: CObjectRetrievalManager::Release, public
//
// Synopsis: IRefCountedObject::Release
//
//----------------------------------------------------------------------------
VOID CObjectRetrievalManager::Release () { if ( InterlockedDecrement( (LONG *)&m_cRefs ) == 0 ) { delete this; } }
//+---------------------------------------------------------------------------
//
// Member: CObjectRetrievalManager::RetrieveObjectByUrl, public
//
// Synopsis: object retrieval given an URL
//
//----------------------------------------------------------------------------
BOOL CObjectRetrievalManager::RetrieveObjectByUrl ( LPCWSTR pwszUrl, LPCSTR pszObjectOid, DWORD dwRetrievalFlags, DWORD dwTimeout, LPVOID* ppvObject, PFN_FREE_ENCODED_OBJECT_FUNC* ppfnFreeObject, LPVOID* ppvFreeContext, HCRYPTASYNC hAsyncRetrieve, PCRYPT_CREDENTIALS pCredentials, LPVOID pvVerify, PCRYPT_RETRIEVE_AUX_INFO pAuxInfo ) { BOOL fResult; CRYPT_BLOB_ARRAY cba; PFN_FREE_ENCODED_OBJECT_FUNC pfnFreeObject = NULL; LPVOID pvFreeContext = NULL;
assert( ppfnFreeObject == NULL ); assert( ppvFreeContext == NULL );
//
// Validate arguments and initialize the providers
//
fResult = ValidateRetrievalArguments( pwszUrl, pszObjectOid, dwRetrievalFlags, dwTimeout, ppvObject, hAsyncRetrieve, pCredentials, pvVerify, pAuxInfo );
if ( fResult == TRUE ) { fResult = LoadProviders( pwszUrl, pszObjectOid ); }
//
// For Async support we should prepare here
//
//
// Call the scheme provider to process the retrieval
//
if ( fResult == TRUE ) { // +1 - Online
// 0 - Offline, current time >= earliest online time, hit the wire
// -1 - Offline, current time < earliest onlime time
LONG lStatus;
if ( CRYPT_OFFLINE_CHECK_RETRIEVAL == ( dwRetrievalFlags & ( CRYPT_OFFLINE_CHECK_RETRIEVAL | CRYPT_CACHE_ONLY_RETRIEVAL ) ) ) { lStatus = GetUrlStatusW( pwszUrl, pszObjectOid, dwRetrievalFlags ); } else { lStatus = 1; }
if (lStatus >= 0) { fResult = CallSchemeRetrieveObjectByUrl( pwszUrl, pszObjectOid, dwRetrievalFlags, dwTimeout, &cba, &pfnFreeObject, &pvFreeContext, hAsyncRetrieve, pCredentials, pAuxInfo ); if ( CRYPT_OFFLINE_CHECK_RETRIEVAL == ( dwRetrievalFlags & ( CRYPT_OFFLINE_CHECK_RETRIEVAL | CRYPT_CACHE_ONLY_RETRIEVAL ) ) ) { if ( fResult != TRUE ) { DWORD dwErr = GetLastError(); SetOfflineUrlW( pwszUrl, pszObjectOid, dwRetrievalFlags ); SetLastError( dwErr ); } else if ( lStatus == 0 ) { SetOnlineUrlW( pwszUrl, pszObjectOid, dwRetrievalFlags ); } } } else { SetLastError( (DWORD) ERROR_NOT_CONNECTED ); fResult = FALSE; } }
//
// If we successfully retrieved the object and this is a synchronous
// retrieval, then we call our own OnRetrievalCompletion in order
// to complete the processing
//
if ( ( fResult == TRUE ) && !( dwRetrievalFlags & CRYPT_ASYNC_RETRIEVAL ) ) { fResult = OnRetrievalCompletion( S_OK, pwszUrl, pszObjectOid, dwRetrievalFlags, &cba, pfnFreeObject, pvFreeContext, pvVerify, ppvObject ); }
return( fResult ); }
//+---------------------------------------------------------------------------
//
// Member: CObjectRetrievalManager::CancelAsyncRetrieval, public
//
// Synopsis: cancel asynchronous retrieval
//
//----------------------------------------------------------------------------
BOOL CObjectRetrievalManager::CancelAsyncRetrieval () { SetLastError( (DWORD) E_NOTIMPL ); return( FALSE ); }
//+---------------------------------------------------------------------------
//
// Member: CObjectRetrievalManager::OnRetrievalCompletion, public
//
// Synopsis: completion notification
//
//----------------------------------------------------------------------------
BOOL CObjectRetrievalManager::OnRetrievalCompletion ( DWORD dwCompletionCode, LPCWSTR pwszUrl, LPCSTR pszObjectOid, DWORD dwRetrievalFlags, PCRYPT_BLOB_ARRAY pObject, PFN_FREE_ENCODED_OBJECT_FUNC pfnFreeObject, LPVOID pvFreeContext, LPVOID pvVerify, LPVOID* ppvObject ) { BOOL fResult = FALSE;
//
// If the retrieval was successfully completed, we go about getting the
// appropriate return value for *ppvObject. If an OID was given then
// we must use the context provider to convert the encoded bits into
// a context value. Otherwise, we hand back a buffer with the encoded
// bits
//
if ( dwCompletionCode == (DWORD)S_OK ) { if ( pszObjectOid != NULL ) { fResult = CallContextCreateObjectContext( pszObjectOid, dwRetrievalFlags, pObject, ppvObject );
if ( fResult == TRUE ) { if ( dwRetrievalFlags & CRYPT_VERIFY_CONTEXT_SIGNATURE ) { fResult = ObjectContextVerifySignature( pszObjectOid, *ppvObject, (PCCERT_CONTEXT)pvVerify ); } } } else { CCryptBlobArray cba( pObject, 0 );
fResult = cba.GetArrayInSingleBufferEncodedForm( (PCRYPT_BLOB_ARRAY *)ppvObject ); }
( *pfnFreeObject )( pszObjectOid, pObject, pvFreeContext ); }
//
// We can now unload the providers
//
UnloadProviders();
return( fResult ); }
//+---------------------------------------------------------------------------
//
// Member: CObjectRetrievalManager::ValidateRetrievalArguments, private
//
// Synopsis: validate arguments to RetrieveObjectByUrl
//
//----------------------------------------------------------------------------
BOOL CObjectRetrievalManager::ValidateRetrievalArguments ( LPCWSTR pwszUrl, LPCSTR pszObjectOid, DWORD dwRetrievalFlags, DWORD dwTimeout, LPVOID* ppvObject, HCRYPTASYNC hAsyncRetrieve, PCRYPT_CREDENTIALS pCredentials, LPVOID pvVerify, PCRYPT_RETRIEVE_AUX_INFO pAuxInfo ) { //
// Assume badness :-)
//
SetLastError( (DWORD) E_INVALIDARG );
//
// Must have an URL
//
// It is possible that this will be ok in the async case
// and the URLs will be parameters on the HCRYPTASYNC
//
if ( pwszUrl == NULL ) { return( FALSE ); }
//
// NOTENOTE: For now we fail async support and I know that I have
// other async flag checks below, they are there as a
// reminder :-)
//
if ( dwRetrievalFlags & CRYPT_ASYNC_RETRIEVAL ) { return( FALSE ); }
//
// If we retrieve from the cache then we can't be async
//
if ( ( dwRetrievalFlags & CRYPT_CACHE_ONLY_RETRIEVAL ) && ( dwRetrievalFlags & CRYPT_ASYNC_RETRIEVAL ) ) { return( FALSE ); }
//
// If we retrieve from the wire we can't be only retrieving from the
// cache
//
if ( ( dwRetrievalFlags & CRYPT_WIRE_ONLY_RETRIEVAL ) && ( dwRetrievalFlags & CRYPT_CACHE_ONLY_RETRIEVAL ) ) { return( FALSE ); }
//
// If we are retrieving async we must have an async handle
//
if ( ( dwRetrievalFlags & CRYPT_ASYNC_RETRIEVAL ) && ( hAsyncRetrieve == NULL ) ) { return( FALSE ); }
//
// This is a temporary check since CRYPT_VERIFY_DATA_HASH is not
// yet implemented
//
if ( dwRetrievalFlags & CRYPT_VERIFY_DATA_HASH ) { SetLastError( (DWORD) E_NOTIMPL ); return( FALSE ); }
//
// We can't have both CRYPT_VERIFY_CONTEXT_SIGNATURE and
// CRYPT_VERIFY_DATA_HASH set
//
if ( ( dwRetrievalFlags & ( CRYPT_VERIFY_CONTEXT_SIGNATURE | CRYPT_VERIFY_DATA_HASH ) ) == ( CRYPT_VERIFY_CONTEXT_SIGNATURE | CRYPT_VERIFY_DATA_HASH ) ) { return( FALSE ); }
//
// If either of the above is set, then pvVerify should be non NULL and
// CRYPT_RETRIEVE_MULTIPLE_OBJECTS should not be set
//
if ( ( dwRetrievalFlags & ( CRYPT_VERIFY_CONTEXT_SIGNATURE | CRYPT_VERIFY_DATA_HASH ) ) && ( ( pvVerify == NULL ) || ( dwRetrievalFlags & CRYPT_RETRIEVE_MULTIPLE_OBJECTS ) ) ) { return( FALSE ); }
//
// We must have an out parameter
//
if ( ppvObject == NULL ) { return( FALSE ); }
SetLastError( 0 ); return( TRUE ); }
//+---------------------------------------------------------------------------
//
// Member: CObjectRetrievalManager::LoadProviders, private
//
// Synopsis: load scheme and context providers based on URL and OID resp.
//
//----------------------------------------------------------------------------
BOOL CObjectRetrievalManager::LoadProviders ( LPCWSTR pwszUrl, LPCSTR pszObjectOid ) { WCHAR pwszScheme[INTERNET_MAX_SCHEME_LENGTH+1]; DWORD cchScheme = INTERNET_MAX_SCHEME_LENGTH; CHAR pszScheme[INTERNET_MAX_SCHEME_LENGTH+1]; HRESULT hr = E_UNEXPECTED;
//
// Get the scheme
//
__try {
hr = UrlGetPartW( pwszUrl, pwszScheme, &cchScheme, URL_PART_SCHEME, 0 // dwFlags
); } __except(EXCEPTION_EXECUTE_HANDLER) { hr = E_UNEXPECTED; }
if (S_OK != hr || 0 == cchScheme) { LPWSTR pwsz; DWORD cch;
pwsz = wcschr( pwszUrl, L':' ); if ( pwsz != NULL ) { cch = (DWORD)(pwsz - pwszUrl); if ( cch > INTERNET_MAX_SCHEME_LENGTH ) { return( FALSE ); }
memcpy( pwszScheme, pwszUrl, cch * sizeof(WCHAR) ); pwszScheme[cch] = L'\0'; } else { wcscpy( pwszScheme, L"file" ); } }
if (!WideCharToMultiByte( CP_ACP, 0, pwszScheme, -1, pszScheme, sizeof(pszScheme) - 1, NULL, NULL )) { return( FALSE ); }
//
// Use the scheme to load the appropriate scheme provider
//
if ( CryptGetOIDFunctionAddress( hSchemeRetrieveFuncSet, X509_ASN_ENCODING, pszScheme, 0, (LPVOID *)&m_pfnSchemeRetrieve, &m_hSchemeRetrieve ) == FALSE ) { return( FALSE ); }
//
// Load the appropriate context provider using the object oid
//
if ( pszObjectOid != NULL ) { if ( CryptGetOIDFunctionAddress( hContextCreateFuncSet, X509_ASN_ENCODING, pszObjectOid, 0, (LPVOID *)&m_pfnContextCreate, &m_hContextCreate ) == FALSE ) { return( FALSE ); } }
return( TRUE ); }
//+---------------------------------------------------------------------------
//
// Member: CObjectRetrievalManager::UnloadProviders, private
//
// Synopsis: unload scheme and context providers
//
//----------------------------------------------------------------------------
VOID CObjectRetrievalManager::UnloadProviders () { if ( m_hSchemeRetrieve != NULL ) { CryptFreeOIDFunctionAddress( m_hSchemeRetrieve, 0 ); m_hSchemeRetrieve = NULL; }
if ( m_hContextCreate != NULL ) { CryptFreeOIDFunctionAddress( m_hContextCreate, 0 ); m_hContextCreate = NULL; } }
//+---------------------------------------------------------------------------
//
// Member: CObjectRetrievalManager::CallSchemeRetrieveObjectByUrl, private
//
// Synopsis: Call the scheme provider RetrieveObjectByUrl entry point
//
//----------------------------------------------------------------------------
BOOL CObjectRetrievalManager::CallSchemeRetrieveObjectByUrl ( LPCWSTR pwszUrl, LPCSTR pszObjectOid, DWORD dwRetrievalFlags, DWORD dwTimeout, PCRYPT_BLOB_ARRAY pObject, PFN_FREE_ENCODED_OBJECT_FUNC* ppfnFreeObject, LPVOID* ppvFreeContext, HCRYPTASYNC hAsyncRetrieve, PCRYPT_CREDENTIALS pCredentials, PCRYPT_RETRIEVE_AUX_INFO pAuxInfo ) { return( ( *m_pfnSchemeRetrieve ) ( pwszUrl, pszObjectOid, dwRetrievalFlags, dwTimeout, pObject, ppfnFreeObject, ppvFreeContext, hAsyncRetrieve, pCredentials, pAuxInfo ) ); }
//+---------------------------------------------------------------------------
//
// Member: CObjectRetrievalManager::CallContextCreateObjectContext, private
//
// Synopsis: call the context provider CreateObjectContext entry point
//
//----------------------------------------------------------------------------
BOOL CObjectRetrievalManager::CallContextCreateObjectContext ( LPCSTR pszObjectOid, DWORD dwRetrievalFlags, PCRYPT_BLOB_ARRAY pObject, LPVOID* ppvContext ) { return( ( *m_pfnContextCreate ) ( pszObjectOid, dwRetrievalFlags, pObject, ppvContext ) ); }
|