Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1852 lines
42 KiB

/*++
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 <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ole2.h>
#include <windows.h>
#include <dbgutil.h>
#include <iadmw.h>
#include <icrypt.hxx>
#include <secdat.hxx>
#include <secpriv.h>
//
// 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<DWORD>(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"