windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/infocomm/common/capiutil.cxx
2020-09-26 16:20:57 +08:00

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;
}