585 lines
13 KiB
C++
585 lines
13 KiB
C++
|
|
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
capiutil.cxx
|
|
|
|
Abstract:
|
|
|
|
Utility functions for dealing with IIS-CAPI integration
|
|
|
|
Author:
|
|
|
|
Alex Mallet (amallet) 02-Dec-1997
|
|
|
|
--*/
|
|
|
|
#include "tcpdllp.hxx"
|
|
#pragma hdrstop
|
|
|
|
#include <dbgutil.h>
|
|
#include <buffer.hxx>
|
|
#include <ole2.h>
|
|
#include <imd.h>
|
|
#include <mb.hxx>
|
|
|
|
//
|
|
// Local includes
|
|
//
|
|
#include "iiscert.hxx"
|
|
#include "capiutil.hxx"
|
|
|
|
|
|
|
|
BOOL RetrieveBlobFromMetabase(MB *pMB,
|
|
LPTSTR pszKey IN,
|
|
PMETADATA_RECORD pMDR OUT,
|
|
DWORD dwSizeHint OPTIONAL)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Tries to retrieve a value of variable length from the metabase
|
|
|
|
Arguments:
|
|
|
|
pMB - pointer to open MB object
|
|
pszKey - key whose value is to be read
|
|
pMDR - pointer to metadata record to be used when reading the value. The pbMDData member
|
|
will be updated on success
|
|
dwSizeHint - if caller has idea of how big value might be, can set this to number of
|
|
bytes to try first retrieval call with
|
|
|
|
Returns:
|
|
|
|
BOOL indicating whether value was read successfully
|
|
|
|
--*/
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
//
|
|
// If caller has a clue, let's use it
|
|
//
|
|
if ( dwSizeHint )
|
|
{
|
|
pMDR->pbMDData = new UCHAR[dwSizeHint];
|
|
|
|
if ( !(pMDR->pbMDData) )
|
|
{
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
pMDR->dwMDDataLen = (dwSizeHint ? dwSizeHint : 0);
|
|
|
|
fSuccess = pMB->GetData( pszKey,
|
|
pMDR->dwMDIdentifier,
|
|
pMDR->dwMDUserType,
|
|
pMDR->dwMDDataType,
|
|
(VOID *) pMDR->pbMDData,
|
|
&(pMDR->dwMDDataLen),
|
|
pMDR->dwMDAttributes );
|
|
|
|
|
|
if ( !fSuccess )
|
|
{
|
|
//
|
|
// If buffer wasn't big enough, let's try again ...
|
|
//
|
|
if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
|
|
{
|
|
//
|
|
// We were brought up well, so we'll clean stuff up
|
|
//
|
|
if ( dwSizeHint )
|
|
{
|
|
delete [] pMDR->pbMDData;
|
|
}
|
|
|
|
pMDR->pbMDData = new UCHAR[pMDR->dwMDDataLen];
|
|
|
|
if ( !(pMDR->pbMDData) )
|
|
{
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
fSuccess = pMB->GetData( pszKey,
|
|
pMDR->dwMDIdentifier,
|
|
pMDR->dwMDUserType,
|
|
pMDR->dwMDDataType,
|
|
(VOID *) pMDR->pbMDData,
|
|
&(pMDR->dwMDDataLen),
|
|
pMDR->dwMDAttributes );
|
|
|
|
if ( !fSuccess )
|
|
{
|
|
//ah, sod it, can't do anymore
|
|
delete [] pMDR->pbMDData;
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !fSuccess )
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT,
|
|
"RetrieveBlobFromMB failed, 0x%x\n", GetLastError()));
|
|
}
|
|
|
|
return fSuccess;
|
|
|
|
} //RetrieveBlobFromMetabase
|
|
|
|
|
|
BOOL CopyString( OUT LPTSTR *ppszDest,
|
|
IN LPTSTR pszSrc )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
String-copy that uses "new" for memory allocation
|
|
|
|
Arguments:
|
|
|
|
ppszDest - pointer to pointer to dest string
|
|
pszSrc - pointer to source string
|
|
|
|
--*/
|
|
|
|
{
|
|
if ( !pszSrc )
|
|
{
|
|
*ppszDest = NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
*ppszDest = new char[strlen(pszSrc) + 1];
|
|
|
|
if ( !*ppszDest )
|
|
{
|
|
SetLastError( ERROR_OUTOFMEMORY );
|
|
return FALSE;
|
|
}
|
|
|
|
memcpy( *ppszDest, pszSrc, strlen(pszSrc) + 1 );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
OPEN_CERT_STORE_INFO* ReadCertStoreInfoFromMB( IN IMDCOM *pMDObject,
|
|
IN LPTSTR pszMBPath,
|
|
IN BOOL fCTL )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read all the information necessary to open a CAPI store out of the metabase
|
|
|
|
Arguments:
|
|
|
|
pMDObject - pointer to metabase object
|
|
pszMBPath - full path in metabase where cert store info is stored, starting from /
|
|
fCTL - bool indicating whether info is to be used to reconstruct a CTL or a cert
|
|
|
|
Returns:
|
|
|
|
Pointer to filled out OPEN_CERT_STORE_INFO structure on success, NULL on failure.
|
|
Note that only some of the OPEN_CERT_STORE_INFO fields are -required-; currently,
|
|
only the store name is required.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBG_ASSERT( pMDObject );
|
|
DBG_ASSERT( pszMBPath );
|
|
|
|
MB mb( pMDObject );
|
|
BOOL fSuccess = FALSE;
|
|
OPEN_CERT_STORE_INFO *pCertStoreInfo = NULL;
|
|
|
|
pCertStoreInfo = AllocateCertStoreInfo();
|
|
|
|
if ( !pCertStoreInfo )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Try to open the key for reading
|
|
//
|
|
if ( mb.Open( pszMBPath,
|
|
METADATA_PERMISSION_READ ))
|
|
{
|
|
DWORD dwReqDataLen = 0;
|
|
METADATA_RECORD mdr;
|
|
|
|
//
|
|
//Try to retrieve container
|
|
//
|
|
MD_SET_DATA_RECORD(&mdr,
|
|
(fCTL ? MD_SSL_CTL_CONTAINER : MD_SSL_CERT_CONTAINER),
|
|
METADATA_NO_ATTRIBUTES,
|
|
IIS_MD_UT_SERVER, STRING_METADATA,
|
|
NULL,
|
|
0);
|
|
|
|
if ( RetrieveBlobFromMetabase(&mb,
|
|
NULL,
|
|
&mdr) )
|
|
|
|
{
|
|
//
|
|
// Metabase will return empty string if NULL string is stored
|
|
//
|
|
if ( !strcmp( (LPTSTR) mdr.pbMDData, TEXT("")) )
|
|
{
|
|
delete [] mdr.pbMDData;
|
|
pCertStoreInfo->pszContainer = NULL;
|
|
}
|
|
else
|
|
{
|
|
pCertStoreInfo->pszContainer = (LPTSTR) mdr.pbMDData;
|
|
}
|
|
}
|
|
|
|
//
|
|
//Try to retrieve cert provider
|
|
//
|
|
MD_SET_DATA_RECORD(&mdr,
|
|
(fCTL ? MD_SSL_CTL_PROVIDER : MD_SSL_CERT_PROVIDER),
|
|
METADATA_NO_ATTRIBUTES,
|
|
IIS_MD_UT_SERVER, STRING_METADATA,
|
|
NULL,
|
|
0);
|
|
|
|
if ( RetrieveBlobFromMetabase(&mb,
|
|
NULL,
|
|
&mdr) )
|
|
|
|
|
|
{
|
|
//
|
|
// Metabase will return empty string if NULL string is stored
|
|
//
|
|
if ( !strcmp( (LPTSTR) mdr.pbMDData, TEXT("")) )
|
|
{
|
|
delete [] mdr.pbMDData;
|
|
pCertStoreInfo->pszProvider = NULL;
|
|
}
|
|
else
|
|
{
|
|
pCertStoreInfo->pszProvider = (LPTSTR) mdr.pbMDData;
|
|
}
|
|
}
|
|
|
|
//
|
|
//Try to retrieve provider type
|
|
//
|
|
mb.GetDword( NULL,
|
|
(fCTL ? MD_SSL_CTL_PROVIDER_TYPE : MD_SSL_CERT_PROVIDER_TYPE),
|
|
IIS_MD_UT_SERVER,
|
|
&(pCertStoreInfo->dwProvType),
|
|
METADATA_NO_ATTRIBUTES );
|
|
|
|
//
|
|
//Retrieve open flags
|
|
//
|
|
mb.GetDword( NULL,
|
|
(fCTL ? MD_SSL_CTL_OPEN_FLAGS : MD_SSL_CERT_OPEN_FLAGS),
|
|
IIS_MD_UT_SERVER,
|
|
&(pCertStoreInfo->dwFlags),
|
|
METADATA_NO_ATTRIBUTES ) ;
|
|
|
|
//
|
|
//Try to retrieve store name
|
|
//
|
|
MD_SET_DATA_RECORD(&mdr,
|
|
(fCTL ? MD_SSL_CTL_STORE_NAME : MD_SSL_CERT_STORE_NAME),
|
|
METADATA_NO_ATTRIBUTES,
|
|
IIS_MD_UT_SERVER, STRING_METADATA,
|
|
NULL,
|
|
0);
|
|
|
|
if ( !RetrieveBlobFromMetabase(&mb,
|
|
NULL,
|
|
&mdr) )
|
|
|
|
{
|
|
goto EndReadStoreInfo;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Metabase will return empty string if NULL string is stored, but
|
|
// empty name is -NOT- valid !
|
|
//
|
|
if ( !strcmp( (LPTSTR) mdr.pbMDData, TEXT("")) )
|
|
{
|
|
delete [] mdr.pbMDData;
|
|
goto EndReadStoreInfo;
|
|
}
|
|
else
|
|
{
|
|
pCertStoreInfo->pszStoreName = (LPTSTR) mdr.pbMDData;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Everything succeeded
|
|
//
|
|
fSuccess = TRUE;
|
|
}
|
|
|
|
EndReadStoreInfo:
|
|
|
|
if ( !fSuccess )
|
|
{
|
|
DeallocateCertStoreInfo( pCertStoreInfo );
|
|
pCertStoreInfo = NULL;
|
|
}
|
|
|
|
return ( pCertStoreInfo );
|
|
}
|
|
|
|
|
|
OPEN_CERT_STORE_INFO* AllocateCertStoreInfo()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate and initialize the structure used to hold info about cert stores
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Returns:
|
|
|
|
Allocated and initialized structure that should be cleaned up with a call to
|
|
DeallocateCertStoreInfo()
|
|
|
|
--*/
|
|
{
|
|
OPEN_CERT_STORE_INFO *pStoreInfo = new OPEN_CERT_STORE_INFO;
|
|
|
|
if ( pStoreInfo )
|
|
{
|
|
memset(pStoreInfo, 0, sizeof(OPEN_CERT_STORE_INFO));
|
|
}
|
|
|
|
return pStoreInfo;
|
|
}
|
|
|
|
VOID DeallocateCertStoreInfo( OPEN_CERT_STORE_INFO *pInfo )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Clean up the structure used to track information about a cert store
|
|
|
|
Arguments:
|
|
|
|
pInfo - pointer to OPEN_CERT_STORE_INFO structure to be cleaned up
|
|
|
|
Returns:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
|
|
{
|
|
if ( !pInfo )
|
|
{
|
|
return ;
|
|
}
|
|
|
|
if ( pInfo->pszContainer )
|
|
{
|
|
delete [] pInfo->pszContainer;
|
|
pInfo->pszContainer = NULL;
|
|
}
|
|
|
|
if ( pInfo->pszProvider )
|
|
{
|
|
delete pInfo->pszProvider;
|
|
pInfo->pszProvider = NULL;
|
|
}
|
|
|
|
if ( pInfo->pszStoreName )
|
|
{
|
|
delete [] pInfo->pszStoreName;
|
|
pInfo->pszStoreName = NULL;
|
|
}
|
|
|
|
if ( pInfo->hCertStore )
|
|
{
|
|
CertCloseStore( pInfo->hCertStore,
|
|
0 );
|
|
pInfo->hCertStore = NULL;
|
|
}
|
|
|
|
delete pInfo;
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
DuplicateCertStoreInfo( OUT OPEN_CERT_STORE_INFO **ppDestStoreInfo,
|
|
IN OPEN_CERT_STORE_INFO *pSrcStoreInfo )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Make a copy of cert store info
|
|
|
|
Arguments:
|
|
|
|
ppDestStoreInfo - pointer to where copy of pSrcStoreInfo is to be placed
|
|
pSrcStoreInfo - information to be copied
|
|
|
|
Returns:
|
|
|
|
TRUE if copy was successful, FALSE if not
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
*ppDestStoreInfo = NULL;
|
|
OPEN_CERT_STORE_INFO *pNewStore = AllocateCertStoreInfo();
|
|
|
|
if ( !pNewStore )
|
|
{
|
|
SetLastError( ERROR_OUTOFMEMORY);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Copy the relevant items
|
|
//
|
|
if ( pSrcStoreInfo->pszContainer &&
|
|
!CopyString( &pNewStore->pszContainer,
|
|
pSrcStoreInfo->pszContainer ) )
|
|
{
|
|
goto EndDuplicateInfo;
|
|
}
|
|
|
|
if ( pSrcStoreInfo->pszProvider &&
|
|
!CopyString( &pNewStore->pszProvider,
|
|
pSrcStoreInfo->pszProvider ) )
|
|
{
|
|
goto EndDuplicateInfo;
|
|
}
|
|
|
|
//
|
|
// Store name -cannot- be NULL
|
|
//
|
|
if ( !pSrcStoreInfo->pszStoreName )
|
|
{
|
|
DBGPRINTF((DBG_CONTEXT,
|
|
"Null store name !\n"));
|
|
goto EndDuplicateInfo;
|
|
}
|
|
else if ( !CopyString( &pNewStore->pszStoreName,
|
|
pSrcStoreInfo->pszStoreName ) )
|
|
{
|
|
goto EndDuplicateInfo;
|
|
}
|
|
|
|
pNewStore->dwFlags = pSrcStoreInfo->dwFlags;
|
|
pNewStore->dwProvType = pSrcStoreInfo->dwProvType;
|
|
|
|
//
|
|
// Duplicate the handle to the store
|
|
//
|
|
if ( !( pNewStore->hCertStore = CertDuplicateStore(pSrcStoreInfo->hCertStore) ))
|
|
{
|
|
goto EndDuplicateInfo;
|
|
}
|
|
|
|
|
|
//
|
|
// Everything is happy, fill in the pointer
|
|
//
|
|
*ppDestStoreInfo = pNewStore;
|
|
|
|
EndDuplicateInfo:
|
|
|
|
|
|
if ( !(*ppDestStoreInfo) )
|
|
{
|
|
DeallocateCertStoreInfo( pNewStore );
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL ServerAddressHasCAPIInfo( IN MB *pMB,
|
|
IN LPTSTR pszCredPath,
|
|
IN DWORD *adwProperties,
|
|
IN DWORD cProperties )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks whether the given MB path has info associated with it necessary to
|
|
reconstruct a particular CAPI structure eg certificate context, CTL context
|
|
|
|
Arguments:
|
|
|
|
pMB - pointer to metabase object open for reading
|
|
pszCredPath - path to where CAPI info would be stored, relative to pMB object
|
|
adwProperties - array of metabase properties that must exist and be readable for the
|
|
given CAPI object
|
|
cProperties - number of elements in pdwProperties array [ = 2 * # of properties]
|
|
Returns:
|
|
|
|
TRUE if cert info exists, FALSE if not
|
|
|
|
--*/
|
|
{
|
|
|
|
DBG_ASSERT( pMB );
|
|
DBG_ASSERT( pszCredPath );
|
|
|
|
BOOL fAllocated = FALSE;
|
|
BOOL fAllData = TRUE;
|
|
|
|
|
|
//
|
|
// Iterate through each property, trying to retrieve it with a buffer size of zero;
|
|
// If retrieving a property fails for any reason other than a buffer that's too
|
|
// small, assume the property doesn't exist
|
|
//
|
|
for (DWORD i = 0; i < cProperties/2; i++)
|
|
{
|
|
DWORD dwSize = 0;
|
|
|
|
pMB->GetData( pszCredPath,
|
|
adwProperties[2*i],
|
|
IIS_MD_UT_SERVER,
|
|
adwProperties[2*i + 1],
|
|
NULL,
|
|
&dwSize,
|
|
METADATA_NO_ATTRIBUTES );
|
|
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
|
|
{
|
|
fAllData = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return fAllData;
|
|
}
|