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.
626 lines
19 KiB
626 lines
19 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// 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
|
|
) );
|
|
}
|
|
|
|
|