/*++ 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 #include #include #include #include // // 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; }