/*++ Copyright (c) 1997 Microsoft Corporation Module Name: security.cxx Abstract: This module contains the code necessary to implement secure DCOM data transfers on-the-wire. It includes the implementation of the "hooked" (call_as) methods from IMSAdminBase. Author: Keith Moore (keithmo) 17-Feb-1997 Revision History: --*/ #include #include #include #include #include #include #include #include #include #include // // Private constants. // #define ALLOC_MEM(cb) (LPVOID)::LocalAlloc( LPTR, (cb) ) #define FREE_MEM(ptr) (VOID)::LocalFree( (HLOCAL)(ptr) ) #if DBG BOOL g_fEnableSecureChannel = TRUE; #define ENABLE_SECURE_CHANNEL g_fEnableSecureChannel #else #define ENABLE_SECURE_CHANNEL TRUE #endif BOOL g_fStopOnKeyset = TRUE; // // Private prototypes. // VOID CalculateGetAllBufferAttributes( IN PMETADATA_GETALL_RECORD Data, IN DWORD NumEntries, OUT DWORD * TotalBufferLength, OUT BOOL * IsBufferSecure ); HRESULT STDMETHODCALLTYPE IMSAdminBaseW_SetData_Proxy( IMSAdminBaseW __RPC_FAR * This, /* [in] */ METADATA_HANDLE hMDHandle, /* [string][in][unique] */ LPCWSTR pszMDPath, /* [in] */ PMETADATA_RECORD pmdrMDData ) /*++ Routine Description: Set a data object. Arguments: hMDHandle - open handle pszMDPath - path of the meta object with which this data is associated pmdrMDData - data to set Return Value: Status. --*/ { HRESULT result; ADM_SECURE_DATA * secureData; IIS_CRYPTO_STORAGE * sendCrypto; PIIS_CRYPTO_BLOB dataBlob; METADATA_RECORD capturedRecord = {0}; // // Setup locals so we know how to cleanup on exit. // secureData = NULL; sendCrypto = NULL; dataBlob = NULL; result = NO_ERROR; // // Trap the case of a null METADATA_RECORD // if( pmdrMDData == NULL ) { result = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); goto cleanup; } // // Capture the METADATA_RECORD so we can muck with it. // __try { capturedRecord = *pmdrMDData; } __except( EXCEPTION_EXECUTE_HANDLER ) { result = HRESULT_FROM_NT( GetExceptionCode() ); } if( FAILED(result) ) { goto cleanup; } // // If this is a secure data item, then encrypt the data before // sending. // #if DBG if( ENABLE_SECURE_CHANNEL && (capturedRecord.dwMDAttributes & METADATA_SECURE) && ((PVOID)capturedRecord.pbMDData != NULL) ) { #else if( (capturedRecord.dwMDAttributes & METADATA_SECURE) && ((PVOID)capturedRecord.pbMDData != NULL) ) { #endif // // Find an ADM_SECURE_DATA object for "This". // secureData = ADM_SECURE_DATA::FindOrAddAndReferenceClientSecureData( This ); if( secureData == NULL ) { result = MD_ERROR_SECURE_CHANNEL_FAILURE; goto cleanup; } // // Get the appropriate crypto storage object. This will perform // key exchange if necessary. // result = secureData->GetClientSendCryptoStorage( &sendCrypto, This ); DBG_ASSERT( SUCCEEDED( result ) || !g_fStopOnKeyset ); if( FAILED(result) ) { goto cleanup; } // // Protect ourselves from malicious users. // __try { // // Encrypt the data. // result = sendCrypto->EncryptData( &dataBlob, (PVOID)capturedRecord.pbMDData, capturedRecord.dwMDDataLen, 0 // dwRegType ); } __except( EXCEPTION_EXECUTE_HANDLER ) { result = HRESULT_FROM_NT(GetExceptionCode()); } DBG_ASSERT( SUCCEEDED( result ) || !g_fStopOnKeyset ); if( FAILED(result) ) { goto cleanup; } // // Update the fields of the captured metadata record so the // RPC runtime will send the data to the server. // capturedRecord.pbMDData = (PBYTE)dataBlob; capturedRecord.dwMDDataLen = IISCryptoGetBlobLength( dataBlob ); } // // Call through to the "real" remoted API to get this over to the // server. // result = IMSAdminBaseW_R_SetData_Proxy( This, hMDHandle, pszMDPath, &capturedRecord ); cleanup: DBG_ASSERT( !g_fStopOnKeyset || ( ( result != NTE_BAD_KEYSET ) && ( result != NTE_KEYSET_NOT_DEF ) && ( result != NTE_KEYSET_ENTRY_BAD ) && ( result != NTE_BAD_KEYSET_PARAM ) ) ); if( dataBlob != NULL ) { IISCryptoFreeBlob( dataBlob ); } if( secureData != NULL ) { secureData->Dereference(); } return result; } // IMSAdminBaseW_SetData_Proxy HRESULT STDMETHODCALLTYPE IMSAdminBaseW_SetData_Stub( IMSAdminBaseW __RPC_FAR * This, /* [in] */ METADATA_HANDLE hMDHandle, /* [string][in][unique] */ LPCWSTR pszMDPath, /* [in] */ PMETADATA_RECORD pmdrMDData ) /*++ Routine Description: Set a data object. Arguments: hMDHandle - open handle pszMDPath - path of the meta object with which this data is associated pmdrMDData - data to set Return Value: Status. --*/ { HRESULT result; ADM_SECURE_DATA * secureData; IIS_CRYPTO_STORAGE * recvCrypto; METADATA_RECORD capturedRecord; DWORD clearDataType; // // Setup locals so we know how to cleanup on exit. // secureData = NULL; recvCrypto = NULL; result = NO_ERROR; // // Capture the metadata record so we can muck with it. // capturedRecord = *pmdrMDData; // // If this is a secure data item, then decrypt the data before // passing it to the actual implementation object. // #if DBG if( ENABLE_SECURE_CHANNEL && (capturedRecord.dwMDAttributes & METADATA_SECURE) && (capturedRecord.pbMDData != NULL) ) { #else if( (capturedRecord.dwMDAttributes & METADATA_SECURE) && (capturedRecord.pbMDData != NULL) ) { #endif // // Find an ADM_SECURE_DATA object for "This". // secureData = ADM_SECURE_DATA::FindAndReferenceServerSecureData( This, TRUE // CreateIfNotFound ); if( secureData == NULL ) { result = MD_ERROR_SECURE_CHANNEL_FAILURE; goto cleanup; } // // Get the appropriate crypto storage object. // result = secureData->GetServerReceiveCryptoStorage( &recvCrypto ); DBG_ASSERT( SUCCEEDED( result ) || !g_fStopOnKeyset ); if ( FAILED(result) ) { goto cleanup; } // // Decrypt the data, then replace the pointer in the metadata // record. // result = recvCrypto->DecryptData( (PVOID *)&capturedRecord.pbMDData, &capturedRecord.dwMDDataLen, &clearDataType, (PIIS_CRYPTO_BLOB)capturedRecord.pbMDData ); DBG_ASSERT( SUCCEEDED( result ) || !g_fStopOnKeyset ); if( FAILED(result) ) { goto cleanup; } } // // Call through to the "real" server stub to set the data. // result = This->SetData( hMDHandle, pszMDPath, &capturedRecord ); cleanup: DBG_ASSERT( !g_fStopOnKeyset || ( ( result != NTE_BAD_KEYSET ) && ( result != NTE_KEYSET_NOT_DEF ) && ( result != NTE_KEYSET_ENTRY_BAD ) && ( result != NTE_BAD_KEYSET_PARAM ) ) ); if( secureData != NULL ) { secureData->Dereference(); } return result; } // IMSAdminBaseW_SetData_Stub HRESULT STDMETHODCALLTYPE IMSAdminBaseW_GetData_Proxy( IMSAdminBaseW __RPC_FAR * This, /* [in] */ METADATA_HANDLE hMDHandle, /* [string][in][unique] */ LPCWSTR pszMDPath, /* [out][in] */ PMETADATA_RECORD pmdrMDData, /* [out] */ DWORD __RPC_FAR *pdwMDRequiredDataLen ) /*++ Routine Description: Get one metadata value Arguments: hMDHandle - open handle pszMDPath - path of the meta object with which this data is associated pmdrMDData - data structure pdwMDRequiredDataLen - updated with required length Return Value: Status. --*/ { HRESULT result; ADM_SECURE_DATA * secureData; IIS_CRYPTO_STORAGE * recvCrypto; IIS_CRYPTO_BLOB *dataBlob; METADATA_RECORD capturedRecord; PVOID dataBuffer; DWORD dataBufferLength; DWORD dataBufferType; // // Setup locals so we know how to cleanup on exit. // secureData = NULL; recvCrypto = NULL; dataBlob = NULL; // // Trap the case of a null METADATA_RECORD // if( pmdrMDData == NULL ) { result = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); goto cleanup; } // // Find an ADM_SECURE_DATA object for "This". // secureData = ADM_SECURE_DATA::FindOrAddAndReferenceClientSecureData( This ); if( secureData == NULL ) { result = MD_ERROR_SECURE_CHANNEL_FAILURE; goto cleanup; } // // Get the appropriate crypto storage object. This will perform // key exchange if necessary. // result = secureData->GetClientReceiveCryptoStorage( &recvCrypto, This ); if( FAILED(result) ) { goto cleanup; } // // Capture the METADATA_RECORD so we can muck with it. // __try { capturedRecord = *pmdrMDData; } __except( EXCEPTION_EXECUTE_HANDLER ) { result = HRESULT_FROM_NT( GetExceptionCode() ); } if( FAILED(result) ) { goto cleanup; } // // Call through to the "real" remoted API to get the data from // the server. Note that we set the data pointer to NULL before // calling the remoted API. This prevents the RPC runtime from // sending plaintext data over to the server. // capturedRecord.pbMDData = NULL; result = IMSAdminBaseW_R_GetData_Proxy( This, hMDHandle, pszMDPath, &capturedRecord, pdwMDRequiredDataLen, &dataBlob ); if( FAILED(result) ) { goto cleanup; } // // Decrypt the data if necessary. This method properly handles // cleartext (unencrypted) blobs. // result = recvCrypto->DecryptData( &dataBuffer, &dataBufferLength, &dataBufferType, dataBlob ); if( FAILED(result) ) { goto cleanup; } // // Copy it back to the user. // __try { if( pmdrMDData->dwMDDataLen >= dataBufferLength ) { RtlCopyMemory( pmdrMDData->pbMDData, dataBuffer, dataBufferLength ); pmdrMDData->dwMDDataLen = dataBufferLength; pmdrMDData->dwMDIdentifier = capturedRecord.dwMDIdentifier; pmdrMDData->dwMDAttributes = capturedRecord.dwMDAttributes; pmdrMDData->dwMDUserType = capturedRecord.dwMDUserType; pmdrMDData->dwMDDataType = capturedRecord.dwMDDataType; pmdrMDData->dwMDDataTag = capturedRecord.dwMDDataTag; } else { *pdwMDRequiredDataLen = dataBufferLength; result = RETURNCODETOHRESULT( ERROR_INSUFFICIENT_BUFFER ); } } __except( EXCEPTION_EXECUTE_HANDLER ) { result = HRESULT_FROM_NT( GetExceptionCode() ); } if( FAILED(result) ) { goto cleanup; } cleanup: if( secureData != NULL ) { secureData->Dereference(); } if( dataBlob != NULL ) { ::IISCryptoFreeBlob( dataBlob ); } return result; } // IMSAdminBaseW_GetData_Proxy HRESULT STDMETHODCALLTYPE IMSAdminBaseW_GetData_Stub( IMSAdminBaseW __RPC_FAR * This, /* [in] */ METADATA_HANDLE hMDHandle, /* [string][in][unique] */ LPCWSTR pszMDPath, /* [out][in] */ PMETADATA_RECORD pmdrMDData, /* [out] */ DWORD __RPC_FAR *pdwMDRequiredDataLen, /* [out] */ struct _IIS_CRYPTO_BLOB __RPC_FAR *__RPC_FAR *ppDataBlob ) /*++ Routine Description: Get one metadata value Arguments: hMDHandle - open handle pszMDPath - path of the meta object with which this data is associated pmdrMDData - data structure pdwMDRequiredDataLen - updated with required length ppDataBlob - Receives a blob for the encrypted data. Return Value: Status. --*/ { HRESULT result; ADM_SECURE_DATA * secureData; IIS_CRYPTO_STORAGE * sendCrypto; IIS_CRYPTO_BLOB *dataBlob; PVOID dataBuffer; // // Setup locals so we know how to cleanup on exit. // secureData = NULL; sendCrypto = NULL; dataBuffer = NULL; dataBlob = NULL; // // Allocate a temporary memory block for the meta data. Use the // same size as the user passed into the API. // dataBuffer = ALLOC_MEM( pmdrMDData->dwMDDataLen ); if( dataBuffer == NULL ) { result = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY ); goto cleanup; } pmdrMDData->pbMDData = (PBYTE)dataBuffer; // // Call through to the "real" server stub to get the data. // result = This->GetData( hMDHandle, pszMDPath, pmdrMDData, pdwMDRequiredDataLen ); if( FAILED(result) ) { goto cleanup; } // // If this is a secure data item, then we'll need to encrypt it // before returning it to the client. Otherwise, we'll build a // cleartext blob to contain the data. // #if DBG if( ENABLE_SECURE_CHANNEL && pmdrMDData->dwMDAttributes & METADATA_SECURE ) { #else if( pmdrMDData->dwMDAttributes & METADATA_SECURE ) { #endif // // Find an ADM_SECURE_DATA object for "This". // secureData = ADM_SECURE_DATA::FindAndReferenceServerSecureData( This, TRUE // CreateIfNotFound ); if( secureData == NULL ) { result = MD_ERROR_SECURE_CHANNEL_FAILURE; goto cleanup; } // // Get the appropriate crypto storage object. // result = secureData->GetServerSendCryptoStorage( &sendCrypto ); if( FAILED(result) ) { goto cleanup; } // // Encrypt the data. // result = sendCrypto->EncryptData( &dataBlob, (PVOID)pmdrMDData->pbMDData, pmdrMDData->dwMDDataLen, 0 ); if( FAILED(result) ) { goto cleanup; } } else { result = ::IISCryptoCreateCleartextBlob( &dataBlob, (PVOID)pmdrMDData->pbMDData, pmdrMDData->dwMDDataLen ); if( FAILED(result) ) { goto cleanup; } } // // Success! // DBG_ASSERT( SUCCEEDED(result) ); *ppDataBlob = dataBlob; cleanup: // // NULL the data pointer in the METADATA_RECORD so the RPC runtime // won't send the plaintext data back to the client. // pmdrMDData->pbMDData = NULL; if( secureData != NULL ) { secureData->Dereference(); } if( dataBuffer != NULL ) { FREE_MEM( dataBuffer ); } if( FAILED(result) && dataBlob != NULL ) { ::IISCryptoFreeBlob( dataBlob ); } return result; } // IMSAdminBaseW_GetData_Stub HRESULT STDMETHODCALLTYPE IMSAdminBaseW_EnumData_Proxy( IMSAdminBaseW __RPC_FAR * This, /* [in] */ METADATA_HANDLE hMDHandle, /* [string][in][unique] */ LPCWSTR pszMDPath, /* [out][in] */ PMETADATA_RECORD pmdrMDData, /* [in] */ DWORD dwMDEnumDataIndex, /* [out] */ DWORD __RPC_FAR *pdwMDRequiredDataLen ) /*++ Routine Description: Enumerate properties of object. Arguments: hMDHandle - open handle pszMDPath - path of the meta object with which this data is associated pmdrMDData - data structure pdwMDRequiredDataLen - updated with required length Return Value: Status. --*/ { HRESULT result; ADM_SECURE_DATA * secureData; IIS_CRYPTO_STORAGE * recvCrypto; IIS_CRYPTO_BLOB *dataBlob; METADATA_RECORD capturedRecord; PVOID dataBuffer; DWORD dataBufferLength; DWORD dataBufferType; // // Setup locals so we know how to cleanup on exit. // secureData = NULL; recvCrypto = NULL; dataBlob = NULL; // // Trap the case of a null METADATA_RECORD // if( pmdrMDData == NULL ) { result = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); goto cleanup; } // // Find an ADM_SECURE_DATA object for "This". // secureData = ADM_SECURE_DATA::FindOrAddAndReferenceClientSecureData( This ); if( secureData == NULL ) { result = MD_ERROR_SECURE_CHANNEL_FAILURE; goto cleanup; } // // Get the appropriate crypto storage object. This will perform // key exchange if necessary. // result = secureData->GetClientReceiveCryptoStorage( &recvCrypto, This ); if( FAILED(result) ) { goto cleanup; } // // Capture the METADATA_RECORD so we can muck with it. // __try { capturedRecord = *pmdrMDData; } __except( EXCEPTION_EXECUTE_HANDLER ) { result = HRESULT_FROM_NT( GetExceptionCode() ); } if( FAILED(result) ) { goto cleanup; } // // Call through to the "real" remoted API to get the data from // the server. Note that we set the data pointer to NULL before // calling the remoted API. This prevents the RPC runtime from // sending plaintext data over to the server. // capturedRecord.pbMDData = NULL; result = IMSAdminBaseW_R_EnumData_Proxy( This, hMDHandle, pszMDPath, &capturedRecord, dwMDEnumDataIndex, pdwMDRequiredDataLen, &dataBlob ); if( FAILED(result) ) { goto cleanup; } // // Decrypt the data if necessary. This method properly handles // cleartext (unencrypted) blobs. // result = recvCrypto->DecryptData( &dataBuffer, &dataBufferLength, &dataBufferType, dataBlob ); if( FAILED(result) ) { goto cleanup; } // // Copy it back to the user. // __try { if( pmdrMDData->dwMDDataLen >= dataBufferLength ) { RtlCopyMemory( pmdrMDData->pbMDData, dataBuffer, dataBufferLength ); pmdrMDData->dwMDDataLen = dataBufferLength; pmdrMDData->dwMDIdentifier = capturedRecord.dwMDIdentifier; pmdrMDData->dwMDAttributes = capturedRecord.dwMDAttributes; pmdrMDData->dwMDUserType = capturedRecord.dwMDUserType; pmdrMDData->dwMDDataType = capturedRecord.dwMDDataType; pmdrMDData->dwMDDataTag = capturedRecord.dwMDDataTag; } else { *pdwMDRequiredDataLen = dataBufferLength; result = RETURNCODETOHRESULT( ERROR_INSUFFICIENT_BUFFER ); } } __except( EXCEPTION_EXECUTE_HANDLER ) { result = HRESULT_FROM_NT( GetExceptionCode() ); } if( FAILED(result) ) { goto cleanup; } cleanup: if( secureData != NULL ) { secureData->Dereference(); } if( dataBlob != NULL ) { ::IISCryptoFreeBlob( dataBlob ); } return result; } // IMSAdminBaseW_EnumData_Proxy HRESULT STDMETHODCALLTYPE IMSAdminBaseW_EnumData_Stub( IMSAdminBaseW __RPC_FAR * This, /* [in] */ METADATA_HANDLE hMDHandle, /* [string][in][unique] */ LPCWSTR pszMDPath, /* [out][in] */ PMETADATA_RECORD pmdrMDData, /* [in] */ DWORD dwMDEnumDataIndex, /* [out] */ DWORD __RPC_FAR *pdwMDRequiredDataLen, /* [out] */ struct _IIS_CRYPTO_BLOB __RPC_FAR *__RPC_FAR *ppDataBlob ) /*++ Routine Description: Enumerate properties of object. Arguments: hMDHandle - open handle pszMDPath - path of the meta object with which this data is associated pmdrMDData - data structure pdwMDRequiredDataLen - updated with required length ppDataBlob - Receives a blob for the encrypted data. Return Value: Status. --*/ { HRESULT result; ADM_SECURE_DATA * secureData; IIS_CRYPTO_STORAGE * sendCrypto; IIS_CRYPTO_BLOB *dataBlob; PVOID dataBuffer; // // Setup locals so we know how to cleanup on exit. // secureData = NULL; sendCrypto = NULL; dataBuffer = NULL; dataBlob = NULL; // // Allocate a temporary memory block for the meta data. Use the // same size as the user passed into the API. // dataBuffer = ALLOC_MEM( pmdrMDData->dwMDDataLen ); if( dataBuffer == NULL ) { result = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY ); goto cleanup; } pmdrMDData->pbMDData = (PBYTE)dataBuffer; // // Call through to the "real" server stub to get the data. // result = This->EnumData( hMDHandle, pszMDPath, pmdrMDData, dwMDEnumDataIndex, pdwMDRequiredDataLen ); if( FAILED(result) ) { goto cleanup; } // // If this is a secure data item, then we'll need to encrypt it // before returning it to the client. Otherwise, we'll build a // cleartext blob to contain the data. // #if DBG if( ENABLE_SECURE_CHANNEL && pmdrMDData->dwMDAttributes & METADATA_SECURE ) { #else if( pmdrMDData->dwMDAttributes & METADATA_SECURE ) { #endif // // Find an ADM_SECURE_DATA object for "This". // secureData = ADM_SECURE_DATA::FindAndReferenceServerSecureData( This, TRUE // CreateIfNotFound ); if( secureData == NULL ) { result = MD_ERROR_SECURE_CHANNEL_FAILURE; goto cleanup; } // // Get the appropriate crypto storage object. // result = secureData->GetServerSendCryptoStorage( &sendCrypto ); if( FAILED(result) ) { goto cleanup; } // // Encrypt the data. // result = sendCrypto->EncryptData( &dataBlob, (PVOID)pmdrMDData->pbMDData, pmdrMDData->dwMDDataLen, 0 ); if( FAILED(result) ) { goto cleanup; } } else { result = ::IISCryptoCreateCleartextBlob( &dataBlob, (PVOID)pmdrMDData->pbMDData, pmdrMDData->dwMDDataLen ); if( FAILED(result) ) { goto cleanup; } } // // Success! // DBG_ASSERT( SUCCEEDED(result) ); *ppDataBlob = dataBlob; cleanup: // // NULL the data pointer in the METADATA_RECORD so the RPC runtime // won't send the plaintext data back to the client. // pmdrMDData->pbMDData = NULL; if( secureData != NULL ) { secureData->Dereference(); } if( dataBuffer != NULL ) { FREE_MEM( dataBuffer ); } if( FAILED(result) && dataBlob != NULL ) { ::IISCryptoFreeBlob( dataBlob ); } return result; } // IMSAdminBaseW_EnumData_Stub HRESULT STDMETHODCALLTYPE IMSAdminBaseW_GetAllData_Proxy( IMSAdminBaseW __RPC_FAR * This, /* [in] */ METADATA_HANDLE hMDHandle, /* [string][in][unique] */ LPCWSTR pszMDPath, /* [in] */ DWORD dwMDAttributes, /* [in] */ DWORD dwMDUserType, /* [in] */ DWORD dwMDDataType, /* [out] */ DWORD __RPC_FAR *pdwMDNumDataEntries, /* [out] */ DWORD __RPC_FAR *pdwMDDataSetNumber, /* [in] */ DWORD dwMDBufferSize, /* [size_is][out] */ unsigned char __RPC_FAR *pbBuffer, /* [out] */ DWORD __RPC_FAR *pdwMDRequiredBufferSize ) /*++ Routine Description: Gets all data associated with a Meta Object Arguments: hMDHandle - open handle pszMDPath - path of the meta object with which this data is associated dwMDAttributes - flags for the data dwMDUserType - user Type for the data dwMDDataType - type of the data pdwMDNumDataEntries - number of entries copied to Buffer pdwMDDataSetNumber - number associated with this data set dwMDBufferSize - size in bytes of buffer pbBuffer - buffer to store the data pdwMDRequiredBufferSize - updated with required length of buffer Return Value: Status. --*/ { HRESULT result; ADM_SECURE_DATA * secureData; IIS_CRYPTO_STORAGE * recvCrypto; IIS_CRYPTO_BLOB *dataBlob; PVOID dataBuffer; DWORD dataBufferLength; DWORD dataBufferType; // // Setup locals so we know how to cleanup on exit. // secureData = NULL; recvCrypto = NULL; dataBlob = NULL; // // Find an ADM_SECURE_DATA object for "This". // secureData = ADM_SECURE_DATA::FindOrAddAndReferenceClientSecureData( This ); if( secureData == NULL ) { result = MD_ERROR_SECURE_CHANNEL_FAILURE; goto cleanup; } // // Get the appropriate crypto storage object. This will perform // key exchange if necessary. // result = secureData->GetClientReceiveCryptoStorage( &recvCrypto, This ); if( FAILED(result) ) { goto cleanup; } // // Call through to the "real" remoted API to get the data from // the server. // result = IMSAdminBaseW_R_GetAllData_Proxy( This, hMDHandle, pszMDPath, dwMDAttributes, dwMDUserType, dwMDDataType, pdwMDNumDataEntries, pdwMDDataSetNumber, dwMDBufferSize, pdwMDRequiredBufferSize, &dataBlob ); if( FAILED(result) ) { goto cleanup; } // // Decrypt the data if necessary. This method properly handles // cleartext (unencrypted) blobs. // result = recvCrypto->DecryptData( &dataBuffer, &dataBufferLength, &dataBufferType, dataBlob ); if( FAILED(result) ) { goto cleanup; } // // Copy it back to the user. // __try { if( dwMDBufferSize >= dataBufferLength ) { RtlCopyMemory( pbBuffer, dataBuffer, dataBufferLength ); } else { *pdwMDRequiredBufferSize = dataBufferLength; result = RETURNCODETOHRESULT( ERROR_INSUFFICIENT_BUFFER ); } } __except( EXCEPTION_EXECUTE_HANDLER ) { result = HRESULT_FROM_NT( GetExceptionCode() ); } if( FAILED(result) ) { goto cleanup; } cleanup: if( secureData != NULL ) { secureData->Dereference(); } if( dataBlob != NULL ) { ::IISCryptoFreeBlob( dataBlob ); } return result; } // IMSAdminBaseW_GetAllData_Proxy HRESULT STDMETHODCALLTYPE IMSAdminBaseW_GetAllData_Stub( IMSAdminBaseW __RPC_FAR * This, /* [in] */ METADATA_HANDLE hMDHandle, /* [string][in][unique] */ LPCWSTR pszMDPath, /* [in] */ DWORD dwMDAttributes, /* [in] */ DWORD dwMDUserType, /* [in] */ DWORD dwMDDataType, /* [out] */ DWORD __RPC_FAR *pdwMDNumDataEntries, /* [out] */ DWORD __RPC_FAR *pdwMDDataSetNumber, /* [in] */ DWORD dwMDBufferSize, /* [out] */ DWORD __RPC_FAR *pdwMDRequiredBufferSize, /* [out] */ struct _IIS_CRYPTO_BLOB __RPC_FAR *__RPC_FAR *ppDataBlob ) /*++ Routine Description: Gets all data associated with a Meta Object Arguments: hMDHandle - open handle pszMDPath - path of the meta object with which this data is associated dwMDAttributes - flags for the data dwMDUserType - user Type for the data dwMDDataType - type of the data pdwMDNumDataEntries - number of entries copied to Buffer pdwMDDataSetNumber - number associated with this data set dwMDBufferSize - size in bytes of buffer pdwMDRequiredBufferSize - updated with required length of buffer ppDataBlob - Receives a blob for the encrypted data. Return Value: Status. --*/ { HRESULT result; ADM_SECURE_DATA * secureData; IIS_CRYPTO_STORAGE * sendCrypto; IIS_CRYPTO_BLOB *dataBlob; PVOID dataBuffer; DWORD getAllBufferLength; BOOL getAllBufferIsSecure; // // Setup locals so we know how to cleanup on exit. // secureData = NULL; sendCrypto = NULL; dataBuffer = NULL; dataBlob = NULL; // // Allocate a temporary memory block for the meta data. Use the // same size as the user passed into the API. // dataBuffer = ALLOC_MEM( dwMDBufferSize ); if( dataBuffer == NULL ) { result = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY ); goto cleanup; } // // Call through to the "real" server stub to get the data. // result = This->GetAllData( hMDHandle, pszMDPath, dwMDAttributes, dwMDUserType, dwMDDataType, pdwMDNumDataEntries, pdwMDDataSetNumber, dwMDBufferSize, (PBYTE)dataBuffer, pdwMDRequiredBufferSize ); if( FAILED(result) ) { goto cleanup; } // // Compute the total size of the METADATA_GETALL_RECORD. Also // take this opportunity to determine if any of the data items // within the record are marked as secure. We'll encrypt the // entire record if any entry is secure. // CalculateGetAllBufferAttributes( (PMETADATA_GETALL_RECORD)dataBuffer, *pdwMDNumDataEntries, &getAllBufferLength, &getAllBufferIsSecure ); // // Encrypt if necessary. // if( getAllBufferIsSecure ) { // // Find an ADM_SECURE_DATA object for "This". // secureData = ADM_SECURE_DATA::FindAndReferenceServerSecureData( This, TRUE // CreateIfNotFound ); if( secureData == NULL ) { result = MD_ERROR_SECURE_CHANNEL_FAILURE; goto cleanup; } // // Get the appropriate crypto storage object. // result = secureData->GetServerSendCryptoStorage( &sendCrypto ); if( FAILED(result) ) { goto cleanup; } // // Encrypt the data. // result = sendCrypto->EncryptData( &dataBlob, dataBuffer, getAllBufferLength, 0 ); if( FAILED(result) ) { goto cleanup; } } else { result = ::IISCryptoCreateCleartextBlob( &dataBlob, dataBuffer, getAllBufferLength ); if( FAILED(result) ) { goto cleanup; } } // // Success! // DBG_ASSERT( SUCCEEDED(result) ); *ppDataBlob = dataBlob; cleanup: if( secureData != NULL ) { secureData->Dereference(); } if( dataBuffer != NULL ) { FREE_MEM( dataBuffer ); } if( FAILED(result) && dataBlob != NULL ) { ::IISCryptoFreeBlob( dataBlob ); } return result; } // IMSAdminBaseW_GetAllData_Stub HRESULT STDMETHODCALLTYPE IMSAdminBaseW_GetServerGuid_Proxy( IMSAdminBaseW __RPC_FAR * ) { return E_FAIL; } // IMSAdminBaseW_GetServerGuid_Proxy HRESULT STDMETHODCALLTYPE IMSAdminBaseW_GetServerGuid_Stub( IMSAdminBaseW __RPC_FAR * This, /* [out] */ GUID __RPC_FAR *pServerGuid) { ADM_SECURE_DATA * secureData; // // Find an ADM_SECURE_DATA object for "This". // secureData = ADM_SECURE_DATA::FindAndReferenceServerSecureData( This, TRUE // CreateIfNotFound ); if( secureData == NULL ) { return MD_ERROR_SECURE_CHANNEL_FAILURE; } *pServerGuid = secureData->GetGuid(); secureData->Dereference(); return ERROR_SUCCESS; } HRESULT STDMETHODCALLTYPE IMSAdminBaseW_KeyExchangePhase1_Proxy( IMSAdminBaseW __RPC_FAR * ) { return E_FAIL; } // IMSAdminBaseW_KeyExchangePhase1_Proxy HRESULT STDMETHODCALLTYPE IMSAdminBaseW_KeyExchangePhase1_Stub( IMSAdminBaseW __RPC_FAR * This, /* [in][unique] */ struct _IIS_CRYPTO_BLOB __RPC_FAR *pClientKeyExchangeKeyBlob, /* [in][unique] */ struct _IIS_CRYPTO_BLOB __RPC_FAR *pClientSignatureKeyBlob, /* [out] */ struct _IIS_CRYPTO_BLOB __RPC_FAR *__RPC_FAR *ppServerKeyExchangeKeyBlob, /* [out] */ struct _IIS_CRYPTO_BLOB __RPC_FAR *__RPC_FAR *ppServerSignatureKeyBlob, /* [out] */ struct _IIS_CRYPTO_BLOB __RPC_FAR *__RPC_FAR *ppServerSessionKeyBlob ) { HRESULT result; ADM_SECURE_DATA * secureData; // // Find an ADM_SECURE_DATA object for "This". // secureData = ADM_SECURE_DATA::FindAndReferenceServerSecureData( This, TRUE // CreateIfNotFound ); if( secureData == NULL ) { return MD_ERROR_SECURE_CHANNEL_FAILURE; } // // Do the phase 1 server-side key exchange. // result = secureData->DoServerSideKeyExchangePhase1( pClientKeyExchangeKeyBlob, pClientSignatureKeyBlob, ppServerKeyExchangeKeyBlob, ppServerSignatureKeyBlob, ppServerSessionKeyBlob ); secureData->Dereference(); return result; } // IMSAdminBaseW_KeyExchangePhase1_Stub HRESULT STDMETHODCALLTYPE IMSAdminBaseW_KeyExchangePhase2_Proxy( IMSAdminBaseW __RPC_FAR * ) { return E_FAIL; } // IMSAdminBaseW_KeyExchangePhase2_Proxy HRESULT STDMETHODCALLTYPE IMSAdminBaseW_KeyExchangePhase2_Stub( IMSAdminBaseW __RPC_FAR * This, /* [in][unique] */ struct _IIS_CRYPTO_BLOB __RPC_FAR *pClientSessionKeyBlob, /* [in][unique] */ struct _IIS_CRYPTO_BLOB __RPC_FAR *pClientHashBlob, /* [out] */ struct _IIS_CRYPTO_BLOB __RPC_FAR *__RPC_FAR *ppServerHashBlob ) { HRESULT result; ADM_SECURE_DATA * secureData; // // Find an ADM_SECURE_DATA object for "This". // secureData = ADM_SECURE_DATA::FindAndReferenceServerSecureData( This, FALSE // CreateIfNotFound ); if( secureData == NULL ) { return MD_ERROR_SECURE_CHANNEL_FAILURE; } // // Do the phase 2 server-side key exchange. // result = secureData->DoServerSideKeyExchangePhase2( pClientSessionKeyBlob, pClientHashBlob, ppServerHashBlob ); secureData->Dereference(); return result; } // IMSAdminBaseW_KeyExchangePhase2_Stub VOID CalculateGetAllBufferAttributes( IN PMETADATA_GETALL_RECORD Data, IN DWORD NumEntries, OUT DWORD * TotalBufferLength, OUT BOOL * IsBufferSecure ) /*++ Routine Description: This routine performs three major functions: 1. It calculates the total size of the METADATA_GETALL_RECORD, including all data. 2. It determines if any of the METADATA_GETALL_RECORDs are marked as secure. Arguments: Data - Pointer to the METADATA_GETALL_RECORD buffer. NumEntries - The number of entries in the buffer. TotalBufferLength - Receives the total buffer length. IsBufferSecure - Receives TRUE if any of the entries are marked secure. Return Value: None. --*/ { PMETADATA_GETALL_RECORD scan; DWORD i; DWORD_PTR usedBufferLength; DWORD_PTR nextOffset; BOOL isSecure; // // Setup. // usedBufferLength = NumEntries * sizeof(METADATA_GETALL_RECORD); isSecure = FALSE; // // Scan the entries, accumulating the total data length. // // Because the individual data entries may be padded. We will // consider the amount of buffer used to be the highest offset // + the length of that record's data. // // While we're at it, determine if any are marked as secure. // for( scan = Data, i = NumEntries ; i > 0 ; scan++, i-- ) { nextOffset = scan->dwMDDataOffset + scan->dwMDDataLen; if( nextOffset > usedBufferLength ) { usedBufferLength = nextOffset; } if( scan->dwMDAttributes & METADATA_SECURE ) { isSecure = ENABLE_SECURE_CHANNEL; } } *TotalBufferLength = static_cast(usedBufferLength); *IsBufferSecure = isSecure; } // CalculateGetAllBufferAttributes VOID WINAPI ReleaseObjectSecurityContextW( IUnknown * Object ) /*++ Routine Description: Releases any security context associated with the specified object. Arguments: Object - The object. Return Value: None. --*/ { ADM_SECURE_DATA * data; // // Find the data associated with the object. // data = ADM_SECURE_DATA::FindAndReferenceServerSecureData( Object, FALSE // CreateIfNotFound ); if( data != NULL ) { // // Dereference the secure data object *twice*, once // to remove the reference added above, and once to // remove the "active" reference. // data->Dereference(); data->Dereference(); } else { ADM_GUID_MAP *pguidmapData; pguidmapData = ADM_GUID_MAP::FindAndReferenceGuidMap( Object ); if( pguidmapData == NULL ) { #if 0 // stop whining DBGPRINTF(( DBG_CONTEXT, "ReleaseObjectSecurityContextW: cannot find data for %08lx\n", Object )); #endif // stop whining } else { // // Dereference the secure data object *twice*, once // to remove the reference added above, and once to // remove the "active" reference. // pguidmapData->Dereference(); pguidmapData->Dereference(); } } } // ReleaseObjectSecurityContextW extern "C" { ULONG STDMETHODCALLTYPE Hooked_IUnknown_Release_Proxy( IUnknown __RPC_FAR * This ) /*++ Routine Description: This is the hooked IUnknown::Release() method (see IADMXP.C for details). Arguments: This - The object being released. Return Value: ULONG - The updated reference count. --*/ { ULONG result; // // AddRef and Release to find out if this is the final release. If so, // destroy any security context associated with this object. // This must be done before the final Release, to avoid a window // between the object getting freed and the security info getting // removed from the lists. // IUnknown_AddRef_Proxy( This ); result = IUnknown_Release_Proxy( This ); if( result == 1 ) { ReleaseObjectSecurityContextW( This ); } // // Call the original release method. // result = IUnknown_Release_Proxy( This ); return result; } // Hooked_IUnknown_Release_Proxy } // extern "C"