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.
 
 
 
 
 
 

3618 lines
105 KiB

// Storage.cpp : Implementation of CStorage
#include "stdafx.h"
#include "mswmdm.h"
#include "Storage.h"
#include "scpinfo.h"
#include "spinfo.h"
#include "loghelp.h"
#include "WMDMStorageEnum.h"
#include "StorageGlobal.h"
#include "scclient.h"
#include "scserver.h"
// We don't want to dll's using our lib to link to drmutil2.lib.
// So disable DRM logging.
#define DISABLE_DRM_LOG
#include "drmerr.h"
#include "wmsstd.h"
#include "key.h"
#include "MediaDevMgr.h"
#include <WMDMUtil.h>
//#define DUMP_FILE
#ifdef DUMP_FILE
#include <stdio.h>
#include <stdlib.h>
#endif
#define STRSAFE_NO_DEPRECATE
#include "strsafe.h"
#define WMDM_TRANSFER_BUFFER_SIZE 57344
//65536
//previous size 10240
/////////////////////////////////////////////////////////////////////////////
// CWMDMStorage
extern CSCPInfo **g_pSCPs;
extern WORD g_wSCPCount;
extern CSecureChannelServer *g_pAppSCServer;
extern CSPInfo **g_pSPs;
typedef struct __INSERTTHREADARGS
{
CWMDMStorage *pThis;
UINT fuMode;
LPWSTR pwszFileSource;
LPWSTR pwszFileDest;
IStream *pOperationStream;
IStream *pProgressStream;
IStream *pUnknownStream;
IWMDMStorage **ppNewObject;
} INSERTTHREADARGS;
typedef struct __DELETETHREADARGS
{
CWMDMStorage *pThis;
IStream *pProgressStream;
UINT fuMode;
} DELETETHREADARGS;
typedef struct __RENAMETHREADARGS
{
CWMDMStorage *pThis;
LPWSTR pwszNewName;
IStream *pProgressStream;
} RENAMETHREADARGS;
typedef struct __READTHREADARGS
{
CWMDMStorage *pThis;
UINT fuMode;
LPWSTR pwszFile;
IStream *pProgressStream;
IStream *pOperationStream;
} READTHREADARGS;
// Construction / Destruction
CWMDMStorage::CWMDMStorage()
: m_pStorage(NULL), m_dwStatus(WMDM_STATUS_READY)
{
GlobalAddRef();
m_pwszRevocationURL = NULL;
m_dwRevocationURLLen = 0;
m_dwRevocationBitFlag = 0;
}
CWMDMStorage::~CWMDMStorage()
{
SAFE_RELEASE(m_pStorage);
CoTaskMemFree( m_pwszRevocationURL );
GlobalRelease();
}
// IWMDMStorage
HRESULT CWMDMStorage::SetAttributes(DWORD dwAttributes, _WAVEFORMATEX *pFormat)
{
HRESULT hr;
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
CORg( WMDM_E_NOTCERTIFIED );
}
}
else
{
CORg( E_FAIL );
}
CORg( m_pStorage->SetAttributes(dwAttributes, pFormat) );
Error:
hrLogDWORD("IWMDMStorage::SetAttributes returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::GetStorageGlobals(IWMDMStorageGlobals **ppStorageGlobals)
{
HRESULT hr;
CComObject<CWMDMStorageGlobal> *pStgGlobal = NULL;
IMDSPStorageGlobals *pSPStgGlobal = NULL;
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
CORg( WMDM_E_NOTCERTIFIED );
}
}
else
{
CORg( E_FAIL );
}
if (!ppStorageGlobals)
{
CORg( E_INVALIDARG );
}
CORg( m_pStorage->GetStorageGlobals(&pSPStgGlobal) );
CORg( CComObject<CWMDMStorageGlobal>::CreateInstance(&pStgGlobal) );
hr = pStgGlobal->QueryInterface(IID_IWMDMStorageGlobals, reinterpret_cast<void**>(ppStorageGlobals));
if (FAILED(hr))
{
delete pStgGlobal;
goto exit;
}
pStgGlobal->SetContainedPointer(pSPStgGlobal, m_wSPIndex);
exit:
Error:
if (pSPStgGlobal)
pSPStgGlobal->Release();
hrLogDWORD("IWMDMStorage::GetStorageGlobals returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::GetAttributes(DWORD *pdwAttributes,
_WAVEFORMATEX *pFormat)
{
HRESULT hr;
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
CORg( WMDM_E_NOTCERTIFIED );
}
}
else
{
CORg( E_FAIL );
}
CORg( m_pStorage->GetAttributes(pdwAttributes, pFormat) );
Error:
hrLogDWORD("IWMDMStorage::GetAttributes returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::GetName(LPWSTR pwszName,
UINT nMaxChars)
{
HRESULT hr;
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
CORg( WMDM_E_NOTCERTIFIED );
}
}
else
{
CORg( E_FAIL );
}
CORg( m_pStorage->GetName(pwszName, nMaxChars) );
Error:
hrLogDWORD("IWMDMStorage::GetName returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::GetDate(PWMDMDATETIME pDateTimeUTC)
{
HRESULT hr;
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
CORg( WMDM_E_NOTCERTIFIED );
}
}
else
{
CORg( E_FAIL );
}
CORg( m_pStorage->GetDate(pDateTimeUTC) );
Error:
hrLogDWORD("IWMDMStorage::GetDate returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::GetSize(DWORD *pdwSizeLow,
DWORD *pdwSizeHigh)
{
HRESULT hr;
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
CORg( WMDM_E_NOTCERTIFIED );
}
}
else
{
CORg( E_FAIL );
}
CORg( m_pStorage->GetSize(pdwSizeLow, pdwSizeHigh) );
Error:
hrLogDWORD("IWMDMStorage::GetSize returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::GetRights(PWMDMRIGHTS *ppRights, UINT *pnRightsCount, BYTE abMac[WMDM_MAC_LENGTH])
{
HRESULT hr;
IMDSPStorageGlobals *pStgGlobals = NULL;
IMDSPObject *pObject = NULL;
ISCPSecureAuthenticate *pSecureAuth = NULL;
ISCPSecureQuery *pSecQuery = NULL;
WORD wCurSCP = 0;
DWORD dwBytesRead;
BYTE *pData = NULL;
UINT fuFlags;
DWORD dwExSize;
DWORD dwMDSize;
DWORD dwRightsSize;
DWORD dwBufferSize=0;
BOOL fUseSCP = FALSE;
CSecureChannelClient *pSCClient = NULL;
CSecureChannelClient *pSPClient = NULL;
HMAC hMAC;
BYTE abTempMAC[SAC_MAC_LEN];
BYTE abMACVerify[SAC_MAC_LEN];
UINT fuTempFlags;
BYTE abSPSessionKey[SAC_SESSION_KEYLEN];
DWORD dwSessionKeyLen = SAC_SESSION_KEYLEN;
if (!ppRights || !pnRightsCount)
{
CORg( E_INVALIDARG );
}
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
CORg( WMDM_E_NOTCERTIFIED );
}
}
else
{
CORg( E_FAIL );
}
g_pSPs[m_wSPIndex]->GetSCClient(&pSPClient);
if (!pSPClient)
{
CORg( E_FAIL );
}
hr = m_pStorage->GetRights(ppRights, pnRightsCount, abTempMAC);
if (SUCCEEDED(hr))
{
// Verify MAC returned by GetRights on the SP
CORg( pSPClient->MACInit(&hMAC) );
CORg( pSPClient->MACUpdate(hMAC, (BYTE*)(*ppRights), sizeof(WMDMRIGHTS) * (*pnRightsCount)) );
CORg( pSPClient->MACUpdate(hMAC, (BYTE*)(pnRightsCount), sizeof(*pnRightsCount)) );
CORg( pSPClient->MACFinal(hMAC, abMACVerify) );
if (memcmp(abMACVerify, abTempMAC, WMDM_MAC_LENGTH) != 0)
{
CORg( WMDM_E_MAC_CHECK_FAILED );
}
}
// If the SP doesn't give us the rights then we should
// try to use the SCP to get the rights.
if ((E_NOTIMPL == hr) || (WMDM_E_NOTSUPPORTED == hr))
{
CORg( m_pStorage->GetStorageGlobals(&pStgGlobals) );
if( g_pSCPs == NULL )
{
CMediaDevMgr::LoadSCPs();
}
for( wCurSCP = 0; wCurSCP < g_wSCPCount; wCurSCP ++ )
{
CORg( g_pSCPs[wCurSCP]->hrGetInterface(&pSecureAuth) );
g_pSCPs[wCurSCP]->GetSCClient(&pSCClient);
if (!pSCClient)
{
CORg( E_FAIL );
}
CORg( pSecureAuth->GetSecureQuery(&pSecQuery) );
CORg( pSecQuery->GetDataDemands(&fuFlags, &dwRightsSize, &dwExSize, &dwMDSize, abTempMAC) );
// Verify MAC returned by GetDataDemands
CORg( pSCClient->MACInit(&hMAC) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&fuFlags), sizeof(fuFlags)) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwRightsSize), sizeof(dwRightsSize)) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwExSize), sizeof(dwExSize)) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwMDSize), sizeof(dwMDSize)) );
CORg( pSCClient->MACFinal(hMAC, abMACVerify) );
if (memcmp(abMACVerify, abTempMAC, WMDM_MAC_LENGTH) != 0)
{
CORg( WMDM_E_MAC_CHECK_FAILED );
}
if (!(fuFlags & WMDM_SCP_RIGHTS_DATA))
{
continue;
}
if (dwBufferSize < (dwExSize>dwRightsSize?dwExSize:dwRightsSize))
{
SAFE_ARRAY_DELETE(pData);
dwBufferSize = dwExSize>dwRightsSize?dwExSize:dwRightsSize;
pData = new BYTE[dwBufferSize];
CPRg( pData );
}
CORg( m_pStorage->QueryInterface(IID_IMDSPObject, reinterpret_cast<void**>(&pObject)) );
CORg( pObject->Open(MDSP_READ) );
hr = WMDM_E_MOREDATA;
while (hr == WMDM_E_MOREDATA)
{
dwBytesRead = dwBufferSize;
CORg( pObject->Read(pData, &dwBytesRead, abTempMAC) );
// BUGBUG: Copy this buffer before decrypting
pSPClient->DecryptParam(pData, dwBytesRead);
// Verify MAC returned by Read on the SP
CORg( pSPClient->MACInit(&hMAC) );
CORg( pSPClient->MACUpdate(hMAC, (BYTE*)pData, dwBytesRead) );
CORg( pSPClient->MACUpdate(hMAC, (BYTE*)(&dwBytesRead), sizeof(dwBytesRead)) );
CORg( pSPClient->MACFinal(hMAC, abMACVerify) );
if (memcmp(abMACVerify, abTempMAC, WMDM_MAC_LENGTH) != 0)
{
CORg( WMDM_E_MAC_CHECK_FAILED );
}
// Create the MAC to send to ExamineData
CORg( pSCClient->MACInit(&hMAC) );
fuTempFlags = WMDM_SCP_EXAMINE_DATA;
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&fuTempFlags), sizeof(fuTempFlags)) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(pData), dwExSize) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwExSize), sizeof(dwExSize)) );
CORg( pSCClient->MACFinal(hMAC, abTempMAC) );
// Encrypt the pData Parameter
pSCClient->EncryptParam(pData, dwExSize);
CORg( pSecQuery->ExamineData(WMDM_SCP_EXAMINE_DATA, NULL, pData, dwExSize, abTempMAC) );
CORg( pSCClient->DecryptParam(pData, dwExSize) );
}
if (hr == S_OK)
{
pSPClient->GetSessionKey(abSPSessionKey);
// Create the MAC to send to GetRights
pSCClient->MACInit(&hMAC);
pSCClient->MACUpdate(hMAC, (BYTE*)(pData), dwRightsSize);
pSCClient->MACUpdate(hMAC, (BYTE*)(&dwRightsSize), sizeof(dwRightsSize));
pSCClient->MACUpdate(hMAC, (BYTE*)(abSPSessionKey), dwSessionKeyLen);
pSCClient->MACUpdate(hMAC, (BYTE*)(&dwSessionKeyLen), sizeof(dwSessionKeyLen));
pSCClient->MACFinal(hMAC, abTempMAC);
// Encrypt the pData Parameter
CORg( pSCClient->EncryptParam(pData, dwRightsSize) );
CORg( pSCClient->EncryptParam((BYTE*)abSPSessionKey, dwSessionKeyLen) );
CORg( pSecQuery->GetRights(pData,
dwRightsSize,
(BYTE*)abSPSessionKey,
dwSessionKeyLen,
pStgGlobals,
ppRights,
pnRightsCount,
abTempMAC) );
// Verify MAC returned by GetRights
pSCClient->MACInit(&hMAC);
pSCClient->MACUpdate(hMAC, (BYTE*)(*ppRights), sizeof(WMDMRIGHTS) * (*pnRightsCount));
pSCClient->MACUpdate(hMAC, (BYTE*)(pnRightsCount), sizeof(*pnRightsCount));
pSCClient->MACFinal(hMAC, abMACVerify);
if (memcmp(abMACVerify, abTempMAC, WMDM_MAC_LENGTH) != 0)
{
hr = WMDM_E_MAC_CHECK_FAILED;
goto exit;
}
break;
}
pObject->Release();
pObject = NULL;
pSecQuery->Release();
pSecQuery = NULL;
}
}
if (SUCCEEDED(hr))
{
// Create the MAC to return to caller
g_pAppSCServer->MACInit(&hMAC);
g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(*ppRights), sizeof(WMDMRIGHTS) * (*pnRightsCount));
g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(pnRightsCount), sizeof(*pnRightsCount));
g_pAppSCServer->MACFinal(hMAC, abMac);
}
Error:
exit:
SAFE_ARRAY_DELETE(pData);
SAFE_RELEASE(pObject);
SAFE_RELEASE(pSecureAuth);
SAFE_RELEASE(pSecQuery);
SAFE_RELEASE(pStgGlobals);
hrLogDWORD("IWMDMStorage::GetRights returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::EnumStorage(IWMDMEnumStorage **ppEnumStorage)
{
HRESULT hr;
CComObject<CWMDMStorageEnum> *pEnumObj = NULL;
IMDSPEnumStorage *pEnumStg = NULL;
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
hr = WMDM_E_NOTCERTIFIED;
goto exit;
}
}
else
{
hr = E_FAIL;
goto exit;
}
CARg( ppEnumStorage );
CORg( m_pStorage->EnumStorage(&pEnumStg) );
CORg( CComObject<CWMDMStorageEnum>::CreateInstance(&pEnumObj) );
hr = pEnumObj->QueryInterface(IID_IWMDMEnumStorage, reinterpret_cast<void**>(ppEnumStorage));
if (FAILED(hr))
{
delete pEnumObj;
goto exit;
}
pEnumObj->SetContainedPointer(pEnumStg, m_wSPIndex);
exit:
Error:
SAFE_RELEASE(pEnumStg);
hrLogDWORD("IWMDMStorage::EnumStorage returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::SendOpaqueCommand(OPAQUECOMMAND *pCommand)
{
HRESULT hr;
HMAC hMAC;
BYTE abTempMAC[WMDM_MAC_LENGTH];
CSecureChannelClient *pSPClient = NULL;
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
CORg( WMDM_E_NOTCERTIFIED );
}
}
else
{
CORg( E_FAIL );
}
if( pCommand == NULL ||
((pCommand->pData == NULL) && (pCommand->dwDataLen > 0)) )
{
CORg( E_INVALIDARG );
}
g_pSPs[m_wSPIndex]->GetSCClient(&pSPClient);
if (!pSPClient)
{
CORg( E_FAIL );
}
// Verify MAC on command
CORg( g_pAppSCServer->MACInit(&hMAC) );
CORg( g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(&(pCommand->guidCommand)), sizeof(pCommand->guidCommand)) );
CORg( g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(&(pCommand->dwDataLen)), sizeof(pCommand->dwDataLen)) );
if (pCommand->pData)
{
CORg( g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(pCommand->pData), pCommand->dwDataLen) );
}
CORg( g_pAppSCServer->MACFinal(hMAC, (BYTE*)abTempMAC) );
if (memcmp((BYTE*)(pCommand->abMAC), abTempMAC, WMDM_MAC_LENGTH) != 0)
{
CORg( WMDM_E_MAC_CHECK_FAILED );
}
// Convert the MAC for the SP
CORg( pSPClient->MACInit(&hMAC) );
CORg( pSPClient->MACUpdate(hMAC, (BYTE*)(&(pCommand->guidCommand)), sizeof(pCommand->guidCommand)) );
CORg( pSPClient->MACUpdate(hMAC, (BYTE*)(&(pCommand->dwDataLen)), sizeof(pCommand->dwDataLen)) );
if (pCommand->pData)
{
CORg( pSPClient->MACUpdate(hMAC, (BYTE*)(pCommand->pData), pCommand->dwDataLen) );
}
CORg( pSPClient->MACFinal(hMAC, (BYTE*)(pCommand->abMAC)) );
CORg( m_pStorage->SendOpaqueCommand(pCommand) );
// Verify the MAC returned by the SP
CORg( pSPClient->MACInit(&hMAC) );
CORg( pSPClient->MACUpdate(hMAC, (BYTE*)(&(pCommand->guidCommand)), sizeof(pCommand->guidCommand)) );
CORg( pSPClient->MACUpdate(hMAC, (BYTE*)(&(pCommand->dwDataLen)), sizeof(pCommand->dwDataLen)) );
if (pCommand->pData)
{
CORg( pSPClient->MACUpdate(hMAC, (BYTE*)(pCommand->pData), pCommand->dwDataLen) );
}
CORg( pSPClient->MACFinal(hMAC, (BYTE*)abTempMAC) );
if (memcmp((BYTE*)(pCommand->abMAC), abTempMAC, WMDM_MAC_LENGTH) != 0)
{
CORg( WMDM_E_MAC_CHECK_FAILED );
}
// Convert the MAC to send back to the Application
CORg( g_pAppSCServer->MACInit(&hMAC) );
CORg( g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(&(pCommand->guidCommand)), sizeof(pCommand->guidCommand)) );
CORg( g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(&(pCommand->dwDataLen)), sizeof(pCommand->dwDataLen)) );
if (pCommand->pData)
{
CORg( g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(pCommand->pData), pCommand->dwDataLen) );
}
CORg( g_pAppSCServer->MACFinal(hMAC, (BYTE*)(pCommand->abMAC)) );
Error:
hrLogDWORD("IWMDMStorage::SendOpaqueCommand returned 0x%08lx", hr, hr);
return hr;
}
// IWMDMStorage2
HRESULT CWMDMStorage::GetStorage( LPCWSTR pszStorageName, IWMDMStorage** ppStorage )
{
HRESULT hr;
IMDSPStorage2* pStorage2 = NULL;
IMDSPStorage* pMDSPStorageFound = NULL;
IMDSPStorage* pMDSubStorage = NULL;
CComObject<CWMDMStorage>* pStgObj = NULL;
CARg( ppStorage );
CARg( pszStorageName );
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
CORg( WMDM_E_NOTCERTIFIED );
}
}
else
{
CORg( E_FAIL );
}
// Get the Storage pointer from the SP (as a IMDSPStorage2)
hr = m_pStorage->QueryInterface(IID_IMDSPStorage2, reinterpret_cast<void**>(&pStorage2));
if( SUCCEEDED(hr) )
{
hr = pStorage2->GetStorage( pszStorageName, &pMDSPStorageFound );
}
// This functionalty is not implemented by the SP. Find the storage by enumerating all storages
if( hr == E_NOTIMPL || hr == E_NOINTERFACE )
{
IMDSPEnumStorage *pEnum = NULL;
WCHAR pswzMDSubStorageName[MAX_PATH];
ULONG ulFetched;
CORg(m_pStorage->EnumStorage(&pEnum));
while( S_OK == pEnum->Next(1, &pMDSubStorage, &ulFetched) )
{
hr = pMDSubStorage->GetName( pswzMDSubStorageName, MAX_PATH );
if( SUCCEEDED(hr) && ( _wcsicmp( pswzMDSubStorageName, pszStorageName ) == 0 ) )
{
// We have found the storage we are looking for.
pMDSPStorageFound = pMDSubStorage;
break;
}
pMDSubStorage->Release();
}
pEnum->Release();
}
// Create a IWMDMStorage object and connect it to the the storage from the SP
if( pMDSPStorageFound != NULL )
{
CORg( CComObject<CWMDMStorage>::CreateInstance(&pStgObj) );
CORg( pStgObj->QueryInterface(IID_IWMDMStorage, reinterpret_cast<void**>(ppStorage)) );
pStgObj->SetContainedPointer(pMDSPStorageFound, m_wSPIndex);
}
// Did not find a matching storage
else if( SUCCEEDED(hr) )
{
hr = S_FALSE;
}
Error:
SAFE_RELEASE(pStorage2);
if( hr != S_OK )
{
ppStorage = NULL;
SAFE_DELETE( pStgObj );
}
hrLogDWORD("IWMDMDevice2::GetStorage returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::SetAttributes2( DWORD dwAttributes,
DWORD dwAttributesEx,
_WAVEFORMATEX *pAudioFormat,
_VIDEOINFOHEADER* pVideoFormat )
{
HRESULT hr;
IMDSPStorage2* pStorage2 = NULL;
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
CORg( WMDM_E_NOTCERTIFIED );
}
}
else
{
CORg( E_FAIL );
}
CORg( m_pStorage->QueryInterface( IID_IMDSPStorage2, reinterpret_cast<void**>(&pStorage2) ) );
CORg( pStorage2->SetAttributes2(dwAttributes,
dwAttributesEx,
pAudioFormat,
pVideoFormat) );
Error:
SAFE_RELEASE(pStorage2);
hrLogDWORD("IWMDMStorage2::SetAttributes2 returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::GetAttributes2( DWORD *pdwAttributes,
DWORD *pdwAttributesEx,
_WAVEFORMATEX *pAudioFormat,
_VIDEOINFOHEADER* pVideoFormat )
{
HRESULT hr;
IMDSPStorage2* pStorage2 = NULL;
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
CORg( WMDM_E_NOTCERTIFIED );
}
}
else
{
CORg( E_FAIL );
}
CORg( m_pStorage->QueryInterface( IID_IMDSPStorage2, reinterpret_cast<void**>(&pStorage2) ) );
CORg( pStorage2->GetAttributes2( pdwAttributes,
pdwAttributesEx,
pAudioFormat,
pVideoFormat) );
Error:
SAFE_RELEASE(pStorage2);
hrLogDWORD("IWMDMStorage2::GetAttributes2 returned 0x%08lx", hr, hr);
return hr;
}
// IWMDMStorageControl
HRESULT CWMDMStorage::Insert(UINT fuMode,
LPWSTR pwszFile,
IWMDMOperation *pOperation,
IWMDMProgress *pProgress,
IWMDMStorage **ppNewObject)
{
HRESULT hr = S_OK;
CORg( Insert2( fuMode,
pwszFile,
NULL,
pOperation,
pProgress,
NULL,
ppNewObject ) );
Error:
hrLogDWORD("IWMDMStorageControl::Insert returned 0x%08lx", hr, hr);
return hr;
}
// IWMDMStorageControl2
HRESULT CWMDMStorage::Insert2(UINT fuMode,
LPWSTR pwszFileSource,
LPWSTR pwszFileDest,
IWMDMOperation* pOperation,
IWMDMProgress* pProgress,
IUnknown* pUnknown,
IWMDMStorage** ppNewObject)
{
HRESULT hr = S_OK;
HANDLE hThread;
DWORD dwThreadID;
INSERTTHREADARGS *pThreadArgs = NULL;
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
hr = WMDM_E_NOTCERTIFIED;
goto exit;
}
}
else
{
hr = E_FAIL;
goto exit;
}
if (fuMode & WMDM_CONTENT_OPERATIONINTERFACE)
{
CARg(pOperation);
}
else
{
CARg(pwszFileSource);
}
if (fuMode & WMDM_MODE_BLOCK)
{
hr = InsertWorker(fuMode,
pwszFileSource,
pwszFileDest,
pOperation,
pProgress,
pUnknown,
ppNewObject);
}
else if (fuMode & WMDM_MODE_THREAD)
{
pThreadArgs = new INSERTTHREADARGS;
CPRg(pThreadArgs);
memset(pThreadArgs, 0, sizeof(INSERTTHREADARGS));
pThreadArgs->pThis = this;
pThreadArgs->fuMode = fuMode;
if (!(fuMode & WMDM_CONTENT_OPERATIONINTERFACE))
{
pThreadArgs->pwszFileSource = new WCHAR[wcslen(pwszFileSource) + 1];
CPRg( pThreadArgs->pwszFileSource );
wcscpy(pThreadArgs->pwszFileSource, pwszFileSource );
}
else
{
// Need to mashal callback interfaces since we are passing it to another thread.
hr = CoMarshalInterThreadInterfaceInStream( __uuidof(IWMDMOperation),
pOperation,
&pThreadArgs->pOperationStream );
}
if( pwszFileDest )
{
pThreadArgs->pwszFileDest = new WCHAR[wcslen(pwszFileDest) + 1];
CPRg( pThreadArgs->pwszFileDest );
wcscpy(pThreadArgs->pwszFileDest, pwszFileDest);
}
if (pProgress)
{
// Need to mashal callback interfaces since we are passing it to another thread.
hr = CoMarshalInterThreadInterfaceInStream( __uuidof(IWMDMProgress),
pProgress,
&pThreadArgs->pProgressStream );
}
if (pUnknown)
{
// Need to mashal callback interfaces since we are passing it to another thread.
hr = CoMarshalInterThreadInterfaceInStream( __uuidof(IUnknown),
pUnknown,
&pThreadArgs->pUnknownStream );
}
pThreadArgs->ppNewObject = ppNewObject;
pThreadArgs->pThis->AddRef();
hThread = CreateThread(NULL, 0, InsertThreadFunc, (void*)pThreadArgs, 0, &dwThreadID);
if (!hThread)
{
pThreadArgs->pThis->Release();
hr = E_FAIL;
goto exit;
}
CloseHandle(hThread);
}
else
{
hr = E_INVALIDARG;
goto exit;
}
exit:
Error:
if ((FAILED(hr)) && (pThreadArgs))
{
SAFE_DELETE(pThreadArgs->pwszFileSource);
SAFE_DELETE(pThreadArgs->pwszFileDest);
SAFE_RELEASE(pThreadArgs->pOperationStream);
SAFE_RELEASE(pThreadArgs->pProgressStream);
SAFE_RELEASE(pThreadArgs->pUnknownStream);
delete pThreadArgs;
}
hrLogDWORD("IWMDMStorageControl::Insert returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::Delete(UINT fuMode, IWMDMProgress *pProgress)
{
HRESULT hr = S_OK;
HANDLE hThread;
DWORD dwThreadID;
DELETETHREADARGS *pThreadArgs = NULL;
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
hr = WMDM_E_NOTCERTIFIED;
goto exit;
}
}
else
{
hr = E_FAIL;
goto exit;
}
if (fuMode & WMDM_MODE_BLOCK)
{
hr = DeleteWorker(fuMode, pProgress);
if (FAILED(hr))
{
goto exit;
}
}
else if (fuMode & WMDM_MODE_THREAD)
{
pThreadArgs = new DELETETHREADARGS;
if (!pThreadArgs)
{
hr = E_OUTOFMEMORY;
goto exit;
}
memset( pThreadArgs, 0, sizeof(DELETETHREADARGS) );
pThreadArgs->pThis = this;
if (pProgress)
{
// Need to mashal callback interfaces since we are passing it to another thread.
hr = CoMarshalInterThreadInterfaceInStream( __uuidof(IWMDMProgress),
pProgress,
&pThreadArgs->pProgressStream );
}
pThreadArgs->fuMode = fuMode;
pThreadArgs->pThis->AddRef();
hThread = CreateThread(NULL, 0, DeleteThreadFunc, (void *)pThreadArgs, 0, &dwThreadID);
if (!hThread)
{
pThreadArgs->pThis->Release();
hr = E_FAIL;
goto exit;
}
CloseHandle(hThread);
}
else
{
hr = E_INVALIDARG;
goto exit;
}
exit:
if ((FAILED(hr)) && (pThreadArgs))
{
SAFE_RELEASE(pThreadArgs->pProgressStream);
delete pThreadArgs;
}
hrLogDWORD("IWMDMStorageControl::Delete returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::Rename(UINT fuMode,
LPWSTR pwszNewName,
IWMDMProgress *pProgress)
{
HRESULT hr = S_OK;
RENAMETHREADARGS *pThreadArgs = NULL;
HANDLE hThread;
DWORD dwThreadID;
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
hr = WMDM_E_NOTCERTIFIED;
goto exit;
}
}
else
{
hr = E_FAIL;
goto exit;
}
if ((!pwszNewName) || (wcslen(pwszNewName) == 0))
{
hr = E_INVALIDARG;
goto exit;
}
if (fuMode & WMDM_MODE_BLOCK)
{
CORg( RenameWorker(pwszNewName, pProgress) );
}
else if (fuMode & WMDM_MODE_THREAD)
{
pThreadArgs = new RENAMETHREADARGS;
CPRg( pThreadArgs );
memset( pThreadArgs, 0, sizeof(RENAMETHREADARGS) );
pThreadArgs->pThis = this;
pThreadArgs->pwszNewName = new WCHAR[wcslen(pwszNewName) + 1];
CPRg( pThreadArgs->pwszNewName );
wcscpy(pThreadArgs->pwszNewName, pwszNewName);
if (pProgress)
{
// Need to mashal callback interfaces since we are passing it to another thread.
hr = CoMarshalInterThreadInterfaceInStream( __uuidof(IWMDMProgress),
pProgress,
&pThreadArgs->pProgressStream );
}
pThreadArgs->pThis->AddRef();
hThread = CreateThread(NULL, 0, RenameThreadFunc, (void *)pThreadArgs, 0, &dwThreadID);
if (!hThread)
{
pThreadArgs->pThis->Release();
hr = E_FAIL;
goto exit;
}
CloseHandle(hThread);
}
else
{
hr = E_INVALIDARG;
goto exit;
}
exit:
Error:
if ((FAILED(hr)) && (pThreadArgs))
{
SAFE_DELETE(pThreadArgs->pwszNewName);
SAFE_RELEASE(pThreadArgs->pProgressStream);
delete pThreadArgs;
}
hrLogDWORD("IWMDMStorageControl::Rename returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::Read(UINT fuMode,
LPWSTR pwszFile,
IWMDMProgress *pProgress,
IWMDMOperation *pOperation)
{
HRESULT hr = S_OK;
READTHREADARGS *pThreadArgs = NULL;
HANDLE hThread;
DWORD dwThreadID;
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
hr = WMDM_E_NOTCERTIFIED;
goto exit;
}
}
else
{
hr = E_FAIL;
goto exit;
}
if (fuMode & WMDM_MODE_BLOCK)
{
CORg( ReadWorker(fuMode, pwszFile, pProgress, pOperation) );
}
else if (fuMode & WMDM_MODE_THREAD)
{
pThreadArgs = new READTHREADARGS;
CPRg( pThreadArgs );
memset( pThreadArgs, 0, sizeof(READTHREADARGS));
pThreadArgs->pThis = this;
pThreadArgs->pwszFile = new WCHAR[wcslen(pwszFile) + 1];
CPRg( pThreadArgs->pwszFile );
wcscpy(pThreadArgs->pwszFile, pwszFile);
if (pProgress)
{
// Need to mashal callback interfaces since we are passing it to another thread.
hr = CoMarshalInterThreadInterfaceInStream( __uuidof(IWMDMProgress),
pProgress,
&pThreadArgs->pProgressStream );
}
if (pOperation)
{
// Need to mashal callback interfaces since we are passing it to another thread.
hr = CoMarshalInterThreadInterfaceInStream( __uuidof(IWMDMOperation),
pOperation,
&pThreadArgs->pOperationStream );
}
pThreadArgs->pThis->AddRef();
hThread = CreateThread(NULL, 0, ReadThreadFunc, (void *)pThreadArgs, 0, &dwThreadID);
if (!hThread)
{
pThreadArgs->pThis->Release();
hr = E_FAIL;
goto exit;
}
CloseHandle(hThread);
}
else
{
hr = E_INVALIDARG;
goto exit;
}
exit:
Error:
if ((FAILED(hr)) && (pThreadArgs))
{
SAFE_DELETE(pThreadArgs->pwszFile);
SAFE_RELEASE(pThreadArgs->pProgressStream);
SAFE_RELEASE(pThreadArgs->pOperationStream);
delete pThreadArgs;
}
hrLogDWORD("IWMDMStorageControl::Read returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::Move(UINT fuMode,
IWMDMStorage *pTargetObject,
IWMDMProgress *pProgress)
{
HRESULT hr = S_OK;
IMDSPObject *pObject = NULL;
IMDSPStorage *pTargetStg = NULL;
CComObject<CWMDMStorage> *pNewMDMStorage = NULL;
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
hr = WMDM_E_NOTCERTIFIED;
goto exit;
}
}
else
{
hr = E_FAIL;
goto exit;
}
CPRg(pTargetObject);
CORg( m_pStorage->QueryInterface(IID_IMDSPObject, reinterpret_cast<void**>(&pObject)) );
((CWMDMStorage *)pTargetObject)->GetContainedPointer(&pTargetStg);
CORg( pObject->Move(fuMode,
pProgress,
pTargetStg) );
exit:
Error:
SAFE_RELEASE(pTargetStg);
SAFE_RELEASE(pObject);
hrLogDWORD("IWMDMStorageControl::Move returned 0x%08lx", hr, hr);
return hr;
}
// IWMDMObjectInfo
HRESULT CWMDMStorage::GetPlayLength(DWORD *pdwLength)
{
HRESULT hr;
IMDSPObjectInfo *pInfo = NULL;
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
hr = WMDM_E_NOTCERTIFIED;
goto exit;
}
}
else
{
hr = E_FAIL;
goto exit;
}
CARg(pdwLength);
CORg( m_pStorage->QueryInterface(IID_IMDSPObjectInfo, reinterpret_cast<void**>(&pInfo)) );
CORg( pInfo->GetPlayLength(pdwLength) );
exit:
Error:
SAFE_RELEASE(pInfo);
hrLogDWORD("IWMDMObjectInfo::GetPlayLength returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::SetPlayLength(DWORD dwLength)
{
HRESULT hr;
IMDSPObjectInfo *pInfo = NULL;
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
hr = WMDM_E_NOTCERTIFIED;
goto exit;
}
}
else
{
hr = E_FAIL;
goto exit;
}
CORg( m_pStorage->QueryInterface(IID_IMDSPObjectInfo, reinterpret_cast<void**>(&pInfo)) );
CORg( pInfo->SetPlayLength(dwLength) );
exit:
Error:
SAFE_RELEASE(pInfo);
hrLogDWORD("IWMDMObjectInfo::SetPlayLength returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::GetPlayOffset(DWORD *pdwOffset)
{
HRESULT hr;
IMDSPObjectInfo *pInfo = NULL;
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
hr = WMDM_E_NOTCERTIFIED;
goto exit;
}
}
else
{
hr = E_FAIL;
goto exit;
}
CARg(pdwOffset);
CORg( m_pStorage->QueryInterface(IID_IMDSPObjectInfo, reinterpret_cast<void**>(&pInfo)) );
CORg( pInfo->GetPlayOffset(pdwOffset) );
exit:
Error:
SAFE_RELEASE(pInfo);
hrLogDWORD("IWMDMObjectInfo::GetPlayOffset returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::SetPlayOffset(DWORD dwOffset)
{
HRESULT hr;
IMDSPObjectInfo *pInfo = NULL;
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
hr = WMDM_E_NOTCERTIFIED;
goto exit;
}
}
else
{
hr = E_FAIL;
goto exit;
}
CORg( m_pStorage->QueryInterface(IID_IMDSPObjectInfo, reinterpret_cast<void**>(&pInfo)) );
CORg( pInfo->SetPlayOffset(dwOffset) );
exit:
Error:
SAFE_RELEASE(pInfo);
hrLogDWORD("IWMDMObjectInfo::SetPlayOffset returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::GetTotalLength(DWORD *pdwLength)
{
HRESULT hr;
IMDSPObjectInfo *pInfo = NULL;
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
hr = WMDM_E_NOTCERTIFIED;
goto exit;
}
}
else
{
hr = E_FAIL;
goto exit;
}
CARg( pdwLength);
CORg( m_pStorage->QueryInterface(IID_IMDSPObjectInfo, reinterpret_cast<void**>(&pInfo)) );
CORg( pInfo->GetTotalLength(pdwLength) );
exit:
Error:
if (pInfo)
pInfo->Release();
hrLogDWORD("IWMDMObjectInfo::GetTotalLength returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::GetLastPlayPosition(DWORD *pdwLastPos)
{
HRESULT hr;
IMDSPObjectInfo *pInfo = NULL;
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
hr = WMDM_E_NOTCERTIFIED;
goto exit;
}
}
else
{
hr = E_FAIL;
goto exit;
}
if (!pdwLastPos)
{
hr = E_INVALIDARG;
goto exit;
}
CORg( m_pStorage->QueryInterface(IID_IMDSPObjectInfo, reinterpret_cast<void**>(&pInfo)) );
CORg( pInfo->GetLastPlayPosition(pdwLastPos) );
exit:
Error:
if (pInfo)
pInfo->Release();
hrLogDWORD("IWMDMObjectInfo::GetLastPlayPosition returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::GetLongestPlayPosition(DWORD *pdwLongestPos)
{
HRESULT hr;
IMDSPObjectInfo *pInfo = NULL;
if (g_pAppSCServer)
{
if(!g_pAppSCServer->fIsAuthenticated())
{
hr = WMDM_E_NOTCERTIFIED;
goto exit;
}
}
else
{
hr = E_FAIL;
goto exit;
}
CARg( pdwLongestPos);
CORg( m_pStorage->QueryInterface(IID_IMDSPObjectInfo, reinterpret_cast<void**>(&pInfo)) );
CORg( pInfo->GetLongestPlayPosition(pdwLongestPos) );
exit:
Error:
if (pInfo)
pInfo->Release();
hrLogDWORD("IWMDMObjectInfo::GetLongestPlayPosition returned 0x%08lx", hr, hr);
return hr;
}
void CWMDMStorage::SetContainedPointer(IMDSPStorage *pStorage, WORD wSPIndex)
{
m_pStorage = pStorage;
m_pStorage->AddRef();
m_wSPIndex = wSPIndex;
return;
}
void CWMDMStorage::GetContainedPointer(IMDSPStorage **ppStorage)
{
*ppStorage = m_pStorage;
(*ppStorage)->AddRef();
return;
}
HRESULT CWMDMStorage::hrCopyToStorageFromFile( UINT fuMode, LPWSTR pwszFileName,
UINT uNewStorageMode, LPWCH wszNewStorageName,
IWMDMStorage*& pNewIWMDMStorage,
IWMDMProgress *pProgress,
IUnknown* pUnknown, BOOL fQuery)
{
USES_CONVERSION;
HRESULT hr;
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD dwBytesRead;
DWORD dwBytesWrite;
BYTE *pData = NULL;
BOOL fRetVal;
CComObject<CWMDMStorage> *pNewWMDMStorage = NULL;
IMDSPStorage *pNewSPStorage = NULL;
ISCPSecureAuthenticate *pSecureAuth = NULL;
ISCPSecureQuery *pSecQuery = NULL;
ISCPSecureQuery2 *pSecQuery2 = NULL;
ISCPSecureExchange *pSecExch = NULL;
IMDSPObject *pObject = NULL;
IMDSPStorageGlobals *pStgGlobals = NULL;
IMDSPDevice *pDevice = NULL;
IMDSPStorage2* pStorage2 = NULL;
WORD wCurSCP=0;
UINT fuFlags;
DWORD dwExSize;
DWORD dwMDSize;
DWORD dwRightsSize;
DWORD dwBufferSize=WMDM_TRANSFER_BUFFER_SIZE;
BOOL fUseSCP = FALSE; // Should data be passed throw an SCP?
BOOL fUsedSCP = FALSE; // Was an SCP used to do the file transfer?
UINT fuReadyFlags;
DWORD dwType;
ULONGLONG qwFileSizeSource;
ULONGLONG qwFileSizeDest;
DWORD dwTicks = 0;
UINT nDecideFlags;
CSecureChannelClient *pSCClient = NULL;
CSecureChannelClient *pSPClient = NULL;
HMAC hMAC;
BYTE abMAC[WMDM_MAC_LENGTH];
BYTE abMACVerify[WMDM_MAC_LENGTH];
UINT fuTempFlags;
DWORD dwAppSec;
BOOL fBeginCalled = FALSE;
DWORD dwSPAppSec;
DWORD dwAPPAppSec;
LPWSTR pwszFileExt = NULL;
DWORD dwSessionKeyLen = SAC_SESSION_KEYLEN;
BYTE abSPSessionKey[SAC_SESSION_KEYLEN];
BOOL fOpen = FALSE;
DWORD dwVersion;
BOOL bEOF = FALSE;
BOOL bFlushSCP = FALSE;
DWORD dwAppAppCertLen; // Length of AppCert of application
DWORD dwSPAppCertLen; // Length of AppCert of SP
BYTE* pAppAppCert = NULL; // Buffer to hold App AppCert
BYTE* pSPAppCert = NULL; // Buffer to hold SP AppCert
#ifdef DUMP_FILE
FILE *hFileDump = NULL;
#endif
// Clear revocation status
CoTaskMemFree( m_pwszRevocationURL );
m_pwszRevocationURL = NULL;
m_dwRevocationURLLen = 0;
m_dwRevocationBitFlag = 0;
pData = new BYTE[WMDM_TRANSFER_BUFFER_SIZE];
if (!pData)
{
hr = E_OUTOFMEMORY;
goto exit;
}
g_pSPs[m_wSPIndex]->GetSCClient(&pSPClient);
if (!pSPClient)
{
hr = E_FAIL;
goto exit;
}
dwVersion = GetVersion();
if (dwVersion < 0x80000000)
{
hFile = CreateFileW(pwszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
}
else
{
hFile = CreateFileA(W2A(pwszFileName), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
}
if (hFile == INVALID_HANDLE_VALUE)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto exit;
}
// If we are reporting progress then we need to tell the app how many ticks we think there will be
qwFileSizeSource = (ULONGLONG)GetFileSize(hFile, NULL);
if (pProgress)
{
fBeginCalled = TRUE;
hr = pProgress->Begin((DWORD)qwFileSizeSource);
if (FAILED(hr))
{
goto exit;
}
}
CORg( m_pStorage->GetStorageGlobals(&pStgGlobals) );
if( g_pSCPs == NULL )
{
CMediaDevMgr::LoadSCPs();
}
// Find the right scp
for( wCurSCP = 0; wCurSCP < g_wSCPCount; wCurSCP++ )
{
hr = g_pSCPs[wCurSCP]->hrGetInterface(&pSecureAuth);
if (FAILED(hr))
{
goto exit;
}
g_pSCPs[wCurSCP]->GetSCClient(&pSCClient);
if (!pSCClient)
{
hr = E_FAIL;
goto exit;
}
CORg( pSecureAuth->GetSecureQuery(&pSecQuery) );
pSecureAuth->Release();
pSecureAuth = NULL;
// GetDataDemands has no incoming MAC so lets clear the buffer.
CORg( pSecQuery->GetDataDemands(&fuFlags, &dwRightsSize, &dwExSize, &dwMDSize, abMAC));
// Verify MAC returned by GetDataDemands
CORg( pSCClient->MACInit(&hMAC) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&fuFlags), sizeof(fuFlags)));
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwRightsSize), sizeof(dwRightsSize)));
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwExSize), sizeof(dwExSize)) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwMDSize), sizeof(dwMDSize)) );
CORg( pSCClient->MACFinal(hMAC, abMACVerify) );
if (memcmp(abMACVerify, abMAC, WMDM_MAC_LENGTH) != 0)
{
hr = WMDM_E_MAC_CHECK_FAILED;
goto exit;
}
if (!(fuFlags & (WMDM_SCP_EXAMINE_DATA | WMDM_SCP_DECIDE_DATA | WMDM_SCP_EXAMINE_EXTENSION)))
{
continue;
}
// If the SCP asked for the file extension then get it from the File
if (fuFlags & WMDM_SCP_EXAMINE_EXTENSION)
{
// Only get the file extension once
if (!pwszFileExt)
{
pwszFileExt = new WCHAR[64];
if (!pwszFileExt)
{
hr = E_OUTOFMEMORY;
goto exit;
}
if (NULL != wcschr(pwszFileName, L'.'))
{
wcsncpy(pwszFileExt, (LPWSTR)(wcsrchr(pwszFileName, L'.') + 1), 64);
}
else
{
SAFE_ARRAY_DELETE(pwszFileExt);
}
}
}
if (dwBufferSize < (dwExSize>dwMDSize?dwExSize:dwMDSize))
{
SAFE_ARRAY_DELETE(pData);
dwBufferSize = dwExSize>dwMDSize?dwExSize:dwMDSize;
pData = new BYTE[dwBufferSize];
if (!pData)
{
hr = E_OUTOFMEMORY;
goto exit;
}
}
// ExamineData
hr = WMDM_E_MOREDATA;
while (hr == WMDM_E_MOREDATA)
{
fRetVal = ReadFile(hFile, pData, dwBufferSize, &dwBytesRead, NULL);
if (!fRetVal)
{
hr = E_FAIL;
goto exit;
}
// Create the MAC to send to ExamineData
CORg( pSCClient->MACInit(&hMAC) );
fuTempFlags = WMDM_SCP_EXAMINE_DATA;
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&fuTempFlags), sizeof(fuTempFlags)));
if (pwszFileExt)
{
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(pwszFileExt), 2 * wcslen(pwszFileExt)));
}
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(pData), dwBytesRead) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwBytesRead), sizeof(dwBytesRead)));
CORg( pSCClient->MACFinal(hMAC, abMAC) );
// Encrypt the pData Parameter
CORg( pSCClient->EncryptParam(pData, dwBytesRead));
CORg( pSecQuery->ExamineData(fuTempFlags, pwszFileExt, pData, dwBytesRead, abMAC));
}
if (0xffffffff == SetFilePointer(hFile, 0, NULL, FILE_BEGIN))
{
goto exit;
}
// MakeDecision
if (hr == S_OK)
{
nDecideFlags = WMDM_SCP_DECIDE_DATA;
if(fuMode & WMDM_MODE_TRANSFER_UNPROTECTED)
{
nDecideFlags |= WMDM_SCP_UNPROTECTED_OUTPUT;
}
if(fuMode & WMDM_MODE_TRANSFER_PROTECTED)
{
nDecideFlags |= WMDM_SCP_PROTECTED_OUTPUT;
}
// If the SCP supports ISCPSecQuery2 use it as a first choice
hr = pSecQuery->QueryInterface( IID_ISCPSecureQuery2, (void**)(&pSecQuery2) );
CORg( g_pAppSCServer->GetAppSec(NULL, &dwAPPAppSec));
CORg( pSPClient->GetAppSec(NULL, &dwSPAppSec));
// Appsec = min(appsec app, appsec SP )
dwAppSec = dwSPAppSec>dwAPPAppSec?dwAPPAppSec:dwSPAppSec;
hr = WMDM_E_MOREDATA;
while (hr == WMDM_E_MOREDATA)
{
fRetVal = ReadFile(hFile, pData, dwBufferSize, &dwBytesRead, NULL);
if (!fRetVal)
{
hr = E_FAIL;
goto exit;
}
CORg( pSPClient->GetSessionKey((BYTE*)abSPSessionKey));
CORg( pSCClient->MACInit(&hMAC) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&nDecideFlags), sizeof(nDecideFlags)));
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(pData), dwBytesRead) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwBytesRead), sizeof(dwBytesRead)) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwAppSec), sizeof(dwAppSec)));
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(abSPSessionKey), dwSessionKeyLen));
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwSessionKeyLen), sizeof(dwSessionKeyLen)));
// Encrypt the pData Parameter
CORg( pSCClient->EncryptParam(pData, dwBytesRead) );
CORg( pSCClient->EncryptParam((BYTE*)abSPSessionKey, dwSessionKeyLen));
// Use MakeDecision2 and pass in AppCerts of App, SP to check for revocation
if( pSecQuery2 && (hr == S_OK) )
{
// Get the AppCert of the App
g_pAppSCServer->GetRemoteAppCert( NULL, &dwAppAppCertLen );
CFRg( dwAppAppCertLen != NULL );
SAFE_ARRAY_DELETE(pAppAppCert);
pAppAppCert = new BYTE[dwAppAppCertLen];
CPRg( pAppAppCert );
g_pAppSCServer->GetRemoteAppCert( pAppAppCert, &dwAppAppCertLen );
// Get the AppCert of the SP
pSPClient->GetRemoteAppCert( NULL, &dwSPAppCertLen );
CFRg( dwSPAppCertLen != NULL )
SAFE_ARRAY_DELETE(pSPAppCert);
pSPAppCert = new BYTE[dwSPAppCertLen];
CPRg( pSPAppCert );
pSPClient->GetRemoteAppCert( pSPAppCert, &dwSPAppCertLen );
// Update mac:ing with the AppCert parameters
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(pAppAppCert), dwAppAppCertLen));
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwAppAppCertLen), sizeof(dwAppAppCertLen)));
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(pSPAppCert), dwSPAppCertLen ));
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwSPAppCertLen ), sizeof(dwSPAppCertLen)));
CORg( pSCClient->MACFinal(hMAC, abMAC));
// Encrypt the 2 AppCerts
CORg( pSCClient->EncryptParam(pAppAppCert, dwAppAppCertLen));
CORg( pSCClient->EncryptParam(pSPAppCert, dwSPAppCertLen) );
qwFileSizeDest = qwFileSizeSource;
hr = pSecQuery2->MakeDecision2( nDecideFlags,
pData,
dwBytesRead,
dwAppSec,
(BYTE*)abSPSessionKey,
dwSessionKeyLen,
pStgGlobals,
pAppAppCert, dwAppAppCertLen, // AppCert App
pSPAppCert, dwSPAppCertLen, // AppCert SP
&m_pwszRevocationURL, // LPSTR - revocation update URL
&m_dwRevocationURLLen, // Length of URL string passed in
&m_dwRevocationBitFlag, // revocation component bitflag
&qwFileSizeDest, pUnknown, // File size, App IUnknown
&pSecExch, // Secure exchange
abMAC);
if( hr == WMDM_E_REVOKED )
{
// If the SP is revoked give it a chance to specify an URL.
UpdateRevocationURL( &m_pwszRevocationURL,
&m_dwRevocationURLLen,
&m_dwRevocationBitFlag );
}
CORg(hr);
}
else
{
CORg( pSCClient->MACFinal(hMAC, abMAC));
qwFileSizeDest = 0;
// Use old MakeDecision call without AppCert revocation check
CORg( pSecQuery->MakeDecision(nDecideFlags,
pData,
dwBytesRead,
dwAppSec,
(BYTE*)abSPSessionKey,
dwSessionKeyLen,
pStgGlobals,
&pSecExch,
abMAC) );
}
}
if (0xffffffff == SetFilePointer(hFile, 0, NULL, FILE_BEGIN))
{
hr = E_FAIL;
goto exit;
}
if (hr == S_OK)
{
fUseSCP = TRUE;
if( pSecExch == NULL ) CORg(E_FAIL);
break;
}
else
{
// If the SCP returns S_FALSE then we don't have rights to do the transfer
hr = WMDM_E_NORIGHTS;
goto exit;
}
}
SAFE_RELEASE( pSecQuery );
SAFE_RELEASE( pSecQuery2 );
}
// If this is only a query then we should just return without copying the file
if (fQuery)
{
hr = S_OK;
goto exit;
}
if (!fUseSCP)
{
CORg( pStgGlobals->GetDevice(&pDevice) );
CORg( pDevice->GetType(&dwType) );
// Do not allow content without and SCP to be transferred to an SDMI only device.
if ((dwType & WMDM_DEVICE_TYPE_SDMI) && (!(dwType & WMDM_DEVICE_TYPE_NONSDMI)))
{
hr = WMDM_E_NORIGHTS;
goto exit;
}
qwFileSizeDest = qwFileSizeSource;
}
// Create the storage we are going to write to.
{
hr = m_pStorage->QueryInterface( __uuidof(IMDSPStorage2), reinterpret_cast<void**>(&pStorage2) );
if( SUCCEEDED(hr) && pStorage2 )
{
hr = pStorage2->CreateStorage2( uNewStorageMode, 0, NULL, NULL, wszNewStorageName, qwFileSizeDest, &pNewSPStorage);
if( hr == E_NOTIMPL )
{
CORg( m_pStorage->CreateStorage(uNewStorageMode, NULL, wszNewStorageName, &pNewSPStorage) );
}
else CORg( hr );
}
else CORg( m_pStorage->CreateStorage(uNewStorageMode, NULL, wszNewStorageName, &pNewSPStorage) );
}
CORg( CComObject<CWMDMStorage>::CreateInstance(&pNewWMDMStorage) );
hr = pNewWMDMStorage->QueryInterface(IID_IWMDMStorage, reinterpret_cast<void**>(&pNewIWMDMStorage));
if (FAILED(hr))
{
delete pNewWMDMStorage;
goto exit;
}
pNewWMDMStorage->SetContainedPointer(pNewSPStorage, m_wSPIndex);
CORg( pNewSPStorage->QueryInterface(IID_IMDSPObject, reinterpret_cast<void**>(&pObject)) );
CORg( pObject->Open(MDSP_WRITE) );
fOpen = TRUE;
fUsedSCP = fUseSCP;
#ifdef DUMP_FILE
hFileDump = fopen("\\Write.wma", "wb");
#endif
// Copy file
while( !bEOF || bFlushSCP )
{
dwBytesWrite = 0;
dwBytesRead = 0;
fuReadyFlags = 0;
// Read data from file
if( !bEOF && !bFlushSCP )
{
dwBytesRead = WMDM_TRANSFER_BUFFER_SIZE;
fRetVal = ReadFile(hFile, pData, WMDM_TRANSFER_BUFFER_SIZE, &dwBytesRead, NULL);
if( dwBytesRead == 0 )
{
break;
}
dwBytesWrite = dwBytesRead;
if (!fRetVal)
{
hr = E_FAIL;
goto exit;
}
bEOF = (WMDM_TRANSFER_BUFFER_SIZE != dwBytesRead);
bFlushSCP = bEOF && fUseSCP;
// Pass file-data to the SCP
if( fUseSCP )
{
// Calculate the MAC to send to the SCP
CORg( pSCClient->MACInit(&hMAC) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(pData), dwBytesRead) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwBytesRead), sizeof(dwBytesRead)) );
CORg( pSCClient->MACFinal(hMAC, abMAC) );
// Encrypt the pData Parameter
CORg( pSCClient->EncryptParam(pData, dwBytesRead) );
CORg( pSecExch->TransferContainerData(pData, dwBytesRead, &fuReadyFlags, abMAC) );
// Verify the MAC on the return parameters
CORg( pSCClient->MACInit(&hMAC) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&fuReadyFlags), sizeof(fuReadyFlags)));
CORg( pSCClient->MACFinal(hMAC, abMACVerify) );
if (memcmp(abMACVerify, abMAC, WMDM_MAC_LENGTH) != 0)
{
hr = WMDM_E_MAC_CHECK_FAILED;
goto exit;
}
// Are we done passing data to the SCP?
bFlushSCP = ((fuReadyFlags & WMDM_SCP_TRANSFER_OBJECTDATA) &&
(fuReadyFlags & WMDM_SCP_NO_MORE_CHANGES))
? TRUE : FALSE;
// The SCP was not interesed in this data, use original data from the file.
if( (fuReadyFlags & WMDM_SCP_NO_MORE_CHANGES) &&
!(fuReadyFlags & WMDM_SCP_TRANSFER_OBJECTDATA) )
{
// Decrypt the original file data
CORg( pSCClient->DecryptParam(pData, dwBytesRead) );
fUseSCP = FALSE;
}
}
}
// Get data back from SCP
if( fUseSCP && (( fuReadyFlags & WMDM_SCP_TRANSFER_OBJECTDATA) || bFlushSCP ))
{
dwBytesWrite = dwBufferSize;
// Calculate the MAC to send to the SCP
CORg( pSCClient->MACInit(&hMAC) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwBytesWrite), sizeof(dwBytesWrite)));
CORg( pSCClient->MACFinal(hMAC, abMAC) );
CORg( pSecExch->ObjectData(pData, &dwBytesWrite, abMAC) );
if(dwBytesWrite == 0)
{
if( bFlushSCP )
{
bFlushSCP = FALSE;
fUseSCP = FALSE; // Done using the SCP
}
continue;
}
// Decrypt the pData Parameter
CORg( pSCClient->DecryptParam(pData, dwBytesWrite) );
// Verify the MAC on the return parameters
CORg( pSCClient->MACInit(&hMAC) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(pData), dwBytesWrite) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwBytesWrite), sizeof(dwBytesWrite)));
CORg( pSCClient->MACFinal(hMAC, abMACVerify) );
if (memcmp(abMACVerify, abMAC, WMDM_MAC_LENGTH) != 0)
{
hr = WMDM_E_MAC_CHECK_FAILED;
goto exit;
}
}
// Write data to SP
if ( ((!fUseSCP) || (fuReadyFlags & WMDM_SCP_TRANSFER_OBJECTDATA) || bFlushSCP )
&& dwBytesWrite > 0 )
{
#ifdef DUMP_FILE
fwrite(pData, sizeof(BYTE), dwBytesWrite, hFileDump);
#endif
// Create MAC to send to SP
CORg( pSPClient->MACInit(&hMAC) );
CORg( pSPClient->MACUpdate(hMAC, (BYTE*)(pData), dwBytesWrite) );
CORg( pSPClient->MACUpdate(hMAC, (BYTE*)(&dwBytesWrite), sizeof(dwBytesWrite)));
CORg( pSPClient->MACFinal(hMAC, abMAC) );
CORg( pSPClient->EncryptParam(pData, dwBytesWrite) );
CORg( pObject->Write(pData, &dwBytesWrite, abMAC) );
if (pProgress)
{
dwTicks += dwBytesRead;
hr = pProgress->Progress(dwTicks);
if (FAILED(hr))
{
goto exit;
}
}
}
} // Copy file
#ifdef DUMP_FILE
fclose(hFileDump);
#endif
// Close content file
if (pObject && fOpen)
{
HRESULT hr2 = pObject->Close();
hr = FAILED(hr)?hr:hr2;
fOpen = FALSE;
}
// SCP::TransferComplete()
if (fUsedSCP)
{
CORg( pSecExch->TransferComplete() );
}
Error:
exit:
if (pObject && fOpen)
{
HRESULT hr2 = pObject->Close();
hr = FAILED(hr)?hr:hr2;
fOpen = FALSE;
}
// Delete new storage file if the copy operation failed.
if( FAILED(hr) && pObject )
{
pObject->Delete(0, NULL);
}
if (pProgress)
{
if (!fBeginCalled)
{
pProgress->Begin(1);
}
// pProgress->End(); // This is done by the caller
}
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
SAFE_ARRAY_DELETE(pAppAppCert);
SAFE_ARRAY_DELETE(pSPAppCert);
SAFE_ARRAY_DELETE(pData);
SAFE_ARRAY_DELETE(pwszFileExt);
SAFE_RELEASE(pDevice);
SAFE_RELEASE(pStgGlobals);
SAFE_RELEASE(pSecureAuth);
SAFE_RELEASE(pSecQuery);
SAFE_RELEASE(pSecQuery2);
SAFE_RELEASE(pStorage2);
SAFE_RELEASE(pSecExch);
SAFE_RELEASE(pObject);
SAFE_RELEASE(pNewSPStorage);
hrLogDWORD("CWMDMStorage::hrCopyToStorageFromFile returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::hrCopyToOperationFromStorage(IWMDMOperation *pOperation, IWMDMProgress *pProgress, IMDSPObject *pObject)
{
//USES_CONVERSION;
HRESULT hr;
BYTE *pData = NULL;
DWORD dwBytes;
DWORD dwTotalBytes = 0;
HMAC hMAC;
BYTE abMAC[WMDM_MAC_LENGTH];
BYTE abMACVerify[WMDM_MAC_LENGTH];
CSecureChannelClient *pSPClient = NULL;
BOOL fOpen = FALSE;
CARg(pOperation);
CARg(pObject);
pData = new BYTE[WMDM_TRANSFER_BUFFER_SIZE];
CPRg(pData);
CORg( pObject->Open(MDSP_READ) );
fOpen = TRUE;
CORg( pOperation->BeginRead() );
g_pSPs[m_wSPIndex]->GetSCClient(&pSPClient);
if (!pSPClient)
{
CORg( E_FAIL );
}
// Copy file
dwBytes = WMDM_TRANSFER_BUFFER_SIZE;
while ((WMDM_TRANSFER_BUFFER_SIZE == dwBytes))
{
dwBytes = WMDM_TRANSFER_BUFFER_SIZE;
CORg( pObject->Read(pData, &dwBytes, abMAC) );
CORg( pSPClient->DecryptParam(pData, dwBytes) );
// Verify MAC returned by Read on the SP
CORg( pSPClient->MACInit(&hMAC) );
CORg( pSPClient->MACUpdate(hMAC, (BYTE*)(pData), dwBytes) );
CORg( pSPClient->MACUpdate(hMAC, (BYTE*)(&dwBytes), sizeof(dwBytes)));
CORg( pSPClient->MACFinal(hMAC, abMACVerify) );
if (memcmp(abMACVerify, abMAC, WMDM_MAC_LENGTH) != 0)
{
hr = WMDM_E_MAC_CHECK_FAILED;
goto exit;
}
// Calculate MAC to hand to operation
CORg( g_pAppSCServer->MACInit(&hMAC) );
CORg( g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(pData), dwBytes) );
CORg( g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(&dwBytes), sizeof(dwBytes)) );
CORg( g_pAppSCServer->MACFinal(hMAC, abMAC) );
// Encrypt the data parameter
CORg( g_pAppSCServer->EncryptParam(pData, dwBytes) );
CORg( pOperation->TransferObjectData(pData, &dwBytes, abMAC) );
dwTotalBytes+=dwBytes;
if (pProgress)
{
CORg( pProgress->Progress(dwTotalBytes) );
}
}
Error:
exit:
HRESULT hr2;
hr2 = pOperation->End(&hr, NULL);
hr = FAILED(hr)?hr:hr2;
if (pObject && fOpen)
{
hr2 = pObject->Close();
hr = FAILED(hr)?hr:hr2;
}
SAFE_ARRAY_DELETE(pData);
hrLogDWORD("CWMDMStorage::hrCopyToOperationFromStorage returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::hrCopyToStorageFromOperation(UINT fuMode, IWMDMOperation *pOperation,
UINT uNewStorageMode, LPWCH wszNewStorageName,
IWMDMStorage*& pNewIWMDMStorage,
IWMDMProgress *pProgress,
IUnknown* pUnknown, BOOL fQuery)
{
HRESULT hr;
BYTE *pData = NULL;
CComObject<CWMDMStorage> *pNewWMDMStorage = NULL;
IMDSPObject *pObject = NULL;
IMDSPStorage *pNewSPStorage = NULL;
IMDSPStorage2 *pStorage2 = NULL;
IMDSPStorageGlobals *pStgGlobals = NULL;
IMDSPDevice *pDevice = NULL;
ISCPSecureAuthenticate *pSecureAuth = NULL;
ISCPSecureQuery *pSecQuery = NULL;
ISCPSecureQuery2 *pSecQuery2 = NULL;
ISCPSecureExchange *pSecExch = NULL;
DWORD dwRightsSize;
DWORD dwExSize;
DWORD dwMDSize;
UINT fuFlags;
UINT fuReadyFlags;
WORD wCurSCP = 0;
BOOL fUseSCP = FALSE; // Should data be passed throw an SCP?
BOOL fUsedSCP = FALSE; // Was an SCP used to do the file transfer?
DWORD dwBufferSize = 0;
DWORD dwBytesRead;
DWORD dwBytesWrite;
DWORD dwType;
ULONGLONG qwFileSizeSource;
ULONGLONG qwFileSizeDest;
UINT nDecideFlags;
DWORD dwTicks = 0;
DWORD dwBufferEnd = 0;
BYTE *pTempData = NULL;
DWORD dwBufferIncrement;
CSecureChannelClient *pSCClient = NULL;
CSecureChannelClient *pSPClient = NULL;
DWORD dwAppSec;
HMAC hMAC;
BYTE abMAC[WMDM_MAC_LENGTH];
BYTE abMACVerify[WMDM_MAC_LENGTH];
UINT fuTempFlags;
BOOL fBeginCalled = FALSE;
DWORD dwSPAppSec;
DWORD dwAPPAppSec;
LPWSTR pwszFileExt = NULL;
// LPWSTR pwszFileName = NULL;
DWORD dwSessionKeyLen = SAC_SESSION_KEYLEN;
BYTE abSPSessionKey[SAC_SESSION_KEYLEN];
BOOL fOpen = FALSE; // Flag indicating if the IMDSPObject::Open has been called
BOOL bEOF = FALSE;
BOOL bFlushSCP = FALSE;
DWORD dwAppAppCertLen; // Length of AppCert of application
DWORD dwSPAppCertLen; // Length of AppCert of SP
BYTE* pAppAppCert = NULL; // Buffer to hold App AppCert
BYTE* pSPAppCert = NULL; // Buffer to hold SP AppCert
// Clear revocation
CoTaskMemFree( m_pwszRevocationURL );
m_pwszRevocationURL = NULL;
m_dwRevocationURLLen = 0;
m_dwRevocationBitFlag = 0;
CARg( pOperation );
// pwszFileName = new WCHAR[512];
// CPRg( pwszFileName );
g_pSPs[m_wSPIndex]->GetSCClient(&pSPClient);
if (!pSPClient)
{
CORg( E_FAIL );
}
CORg( m_pStorage->GetStorageGlobals(&pStgGlobals) );
// Get size of source file
DWORD dwFileSizeLow;
DWORD dwFileSizeHigh;
hr = pOperation->GetObjectTotalSize( &dwFileSizeLow, &dwFileSizeHigh );
if( FAILED(hr) ) qwFileSizeSource = 0;
else qwFileSizeSource = dwFileSizeLow + ((ULONGLONG)dwFileSizeHigh << 32);
if( g_pSCPs == NULL )
{
CMediaDevMgr::LoadSCPs();
}
// Find the right SCP
for( wCurSCP = 0; wCurSCP < g_wSCPCount; wCurSCP++ )
{
CORg( g_pSCPs[wCurSCP]->hrGetInterface(&pSecureAuth));
g_pSCPs[wCurSCP]->GetSCClient(&pSCClient);
if (!pSCClient)
{
CORg( E_FAIL );
}
CORg( pSecureAuth->GetSecureQuery(&pSecQuery) );
pSecureAuth->Release();
pSecureAuth = NULL;
CORg( pSecQuery->GetDataDemands(&fuFlags, &dwRightsSize, &dwExSize, &dwMDSize, abMAC) );
// Verify MAC returned by GetDataDemands
CORg( pSCClient->MACInit(&hMAC) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&fuFlags), sizeof(fuFlags)) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwRightsSize), sizeof(dwRightsSize)) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwExSize), sizeof(dwExSize)) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwMDSize), sizeof(dwMDSize)) );
CORg( pSCClient->MACFinal(hMAC, abMACVerify) );
if (memcmp(abMACVerify, abMAC, WMDM_MAC_LENGTH) != 0)
{
hr = WMDM_E_MAC_CHECK_FAILED;
goto exit;
}
if (!(fuFlags & (WMDM_SCP_EXAMINE_DATA | WMDM_SCP_DECIDE_DATA | WMDM_SCP_EXAMINE_EXTENSION)))
{
continue;
}
// If the SCP asked for the file extension then get it from the file name passed in
if (fuFlags & WMDM_SCP_EXAMINE_EXTENSION)
{
// Only get the file extension once
if (!pwszFileExt)
{
pwszFileExt = new WCHAR[64];
CARg( pwszFileExt);
if (NULL != wcschr(wszNewStorageName, L'.'))
{
wcsncpy(pwszFileExt, (LPWSTR)(wcsrchr(wszNewStorageName, L'.') + 1), 64);
}
else
{
SAFE_ARRAY_DELETE(pwszFileExt);
}
}
}
if (dwBufferSize < (dwExSize>dwMDSize?dwExSize:dwMDSize))
{
SAFE_ARRAY_DELETE(pData);
dwBufferSize = dwExSize>dwMDSize?dwExSize:dwMDSize;
pData = new BYTE[dwBufferSize];
CARg( pData );
}
// ExamineData
hr = WMDM_E_MOREDATA;
dwBufferIncrement = dwBufferSize;
while (hr == WMDM_E_MOREDATA)
{
dwBytesRead = dwBufferSize - dwBufferEnd;
// Calculate MAC to send to TransferObjectData
CORg( g_pAppSCServer->MACInit(&hMAC) );
CORg( g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(pData + dwBufferEnd), dwBytesRead) );
CORg( g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(&dwBytesRead), sizeof(dwBytesRead)) );
CORg( g_pAppSCServer->MACFinal(hMAC, abMAC) );
// Encrypt the data parameter
CORg( g_pAppSCServer->EncryptParam(pData + dwBufferEnd, dwBytesRead) );
CORg( pOperation->TransferObjectData((BYTE *)(pData + dwBufferEnd), &dwBytesRead, abMAC) );
if (dwBytesRead == 0)
{
// BUGBUG: Do we really want to return E_FAIL here?
// If they app returns S_FALSE then there is no more data to transfer
// Since the SCP couldn't decide yet we must fail.
hr = E_FAIL;
break;
}
// Decrypt the data parameter
CORg( g_pAppSCServer->DecryptParam(pData + dwBufferEnd, dwBytesRead) );
CORg( g_pAppSCServer->MACInit(&hMAC) );
CORg( g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(pData + dwBufferEnd), dwBytesRead) );
CORg( g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(&dwBytesRead), sizeof(dwBytesRead)) );
CORg( g_pAppSCServer->MACFinal(hMAC, abMACVerify) );
if (memcmp(abMACVerify, abMAC, WMDM_MAC_LENGTH) != 0)
{
hr = WMDM_E_MAC_CHECK_FAILED;
goto exit;
}
// Create the MAC to send to ExamineData
CORg( pSCClient->MACInit(&hMAC) );
fuTempFlags = WMDM_SCP_EXAMINE_DATA;
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&fuTempFlags), sizeof(fuTempFlags)) );
if (pwszFileExt)
{
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(pwszFileExt), 2 * wcslen(pwszFileExt)) );
}
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(pData + dwBufferEnd), dwBytesRead) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwBytesRead), sizeof(dwBytesRead)) );
CORg( pSCClient->MACFinal(hMAC, abMAC) );
// Encrypt the pData Parameter
CORg( pSCClient->EncryptParam(pData + dwBufferEnd, dwBytesRead) );
CORg( pSecQuery->ExamineData(fuTempFlags, pwszFileExt, (BYTE *)(pData + dwBufferEnd), dwBytesRead, abMAC) );
// Decrypt the data parameter
pSCClient->DecryptParam(pData + dwBufferEnd, dwBytesRead);
if (hr == WMDM_E_MOREDATA)
{
dwBufferSize += dwBufferIncrement;
pTempData = new BYTE[dwBufferSize];
CARg( pTempData );
dwBufferEnd += dwBytesRead;
memcpy(pTempData, pData, dwBufferEnd);
SAFE_ARRAY_DELETE(pData);
pData = pTempData;
pTempData = NULL;
}
}
// MakeDecision
if (hr == S_OK)
{
if (fuMode & WMDM_MODE_TRANSFER_UNPROTECTED)
{
nDecideFlags = WMDM_SCP_DECIDE_DATA | WMDM_SCP_UNPROTECTED_OUTPUT;
}
else
{
nDecideFlags = WMDM_SCP_DECIDE_DATA | WMDM_SCP_PROTECTED_OUTPUT;
}
// If the SCP supports ISCPSecQuery2 use it as a first choice
hr = pSecQuery->QueryInterface( IID_ISCPSecureQuery2, (void**)(&pSecQuery2) );
CORg( g_pAppSCServer->GetAppSec(NULL, &dwAPPAppSec) );
CORg( pSPClient->GetAppSec(NULL, &dwSPAppSec) );
// Appsec = min(appsec app, appsec SP )
dwAppSec = dwSPAppSec>dwAPPAppSec?dwAPPAppSec:dwSPAppSec;
hr = WMDM_E_MOREDATA;
dwBytesRead += dwBufferEnd;
dwBufferEnd = 0;
while (hr == WMDM_E_MOREDATA)
{
CORg( pSPClient->GetSessionKey((BYTE*)abSPSessionKey) );
CORg( pSCClient->MACInit(&hMAC) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&nDecideFlags), sizeof(nDecideFlags)) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(pData + dwBufferEnd), dwBytesRead) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwBytesRead), sizeof(dwBytesRead)) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwAppSec), sizeof(dwAppSec)) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(abSPSessionKey), dwSessionKeyLen) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwSessionKeyLen), sizeof(dwSessionKeyLen)) );
// Encrypt the pData Parameter
CORg( pSCClient->EncryptParam(pData + dwBufferEnd, dwBytesRead) );
CORg( pSCClient->EncryptParam((BYTE*)abSPSessionKey, dwSessionKeyLen) );
// Use MakeDecision2 and pass in AppCerts of App, SP to check for revocation
if( pSecQuery2 )
{
// Get the AppCert of the App
g_pAppSCServer->GetRemoteAppCert( NULL, &dwAppAppCertLen );
CFRg( dwAppAppCertLen != NULL );
SAFE_ARRAY_DELETE(pAppAppCert);
pAppAppCert = new BYTE[dwAppAppCertLen];
CPRg( pAppAppCert );
g_pAppSCServer->GetRemoteAppCert( pAppAppCert, &dwAppAppCertLen );
// Get the AppCert of the SP
pSPClient->GetRemoteAppCert( NULL, &dwSPAppCertLen );
CFRg( dwSPAppCertLen != NULL )
SAFE_ARRAY_DELETE(pSPAppCert);
pSPAppCert = new BYTE[dwSPAppCertLen];
CPRg( pSPAppCert );
pSPClient->GetRemoteAppCert( pSPAppCert, &dwSPAppCertLen );
// Update mac:ing with the AppCert parameters
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(pAppAppCert), dwAppAppCertLen));
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwAppAppCertLen), sizeof(dwAppAppCertLen)));
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(pSPAppCert), dwSPAppCertLen ));
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwSPAppCertLen ), sizeof(dwSPAppCertLen)));
CORg( pSCClient->MACFinal(hMAC, abMAC));
// Encrypt the 2 AppCerts
CORg( pSCClient->EncryptParam(pAppAppCert, dwAppAppCertLen));
CORg( pSCClient->EncryptParam(pSPAppCert, dwSPAppCertLen) );
qwFileSizeDest = qwFileSizeSource;
hr = pSecQuery2->MakeDecision2( nDecideFlags,
pData,
dwBytesRead,
dwAppSec,
(BYTE*)abSPSessionKey,
dwSessionKeyLen,
pStgGlobals,
pAppAppCert, dwAppAppCertLen, // AppCert App
pSPAppCert, dwSPAppCertLen, // AppCert SP
&m_pwszRevocationURL, // String - revocation update URL
&m_dwRevocationURLLen, // Length of URL string passed in
&m_dwRevocationBitFlag, // revocatoin component bitflag
&qwFileSizeDest, pUnknown,
&pSecExch,
abMAC);
if( hr == WMDM_E_REVOKED )
{
// If the SP is revoked give it a chance to specify an URL.
UpdateRevocationURL( &m_pwszRevocationURL,
&m_dwRevocationURLLen,
&m_dwRevocationBitFlag );
}
CORg(hr);
}
else
{
// If this SCP does not support the new ISCPSecureQuery2 interface use the old MakeDecision
CORg( pSCClient->MACFinal(hMAC, abMAC));
qwFileSizeDest = 0;
CORg( pSecQuery->MakeDecision(nDecideFlags,
(BYTE *)(pData + dwBufferEnd),
dwBytesRead,
dwAppSec,
(BYTE*)abSPSessionKey,
dwSessionKeyLen,
pStgGlobals,
&pSecExch,
abMAC) );
}
// Decrypt the data parameter
CORg( pSCClient->DecryptParam(pData + dwBufferEnd, dwBytesRead) );
// SCP needs more data for MakeDecision
if (hr == WMDM_E_MOREDATA)
{
dwBufferSize += dwBufferIncrement;
pTempData = new BYTE[dwBufferSize];
CARg( pTempData );
dwBufferEnd += dwBytesRead;
memcpy(pTempData, pData, dwBufferEnd);
SAFE_ARRAY_DELETE(pData);
pData = pTempData;
pTempData = NULL;
dwBytesRead = dwBufferSize - dwBufferEnd;
// Calculate MAC to send to TransferObjectData
CORg( g_pAppSCServer->MACInit(&hMAC) );
CORg( g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(pData + dwBufferEnd), dwBytesRead) );
CORg( g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(&dwBytesRead), sizeof(dwBytesRead)) );
CORg( g_pAppSCServer->MACFinal(hMAC, abMAC) );
// Encrypt the data parameter
CORg( g_pAppSCServer->EncryptParam(pData + dwBufferEnd, dwBytesRead) );
CORg( pOperation->TransferObjectData((BYTE *)(pData + dwBufferEnd), &dwBytesRead, abMAC) );
if (dwBytesRead == 0)
{
// BUGBUG: Do we really want to return E_FAIL here?
// If they app returns S_FALSE then there is no more data to transfer
// Since the SCP couldn't decide yet we must fail.
hr = E_FAIL;
break;
}
// Decrypt the data parameter
CORg( g_pAppSCServer->DecryptParam(pData + dwBufferEnd, dwBytesRead) );
CORg( g_pAppSCServer->MACInit(&hMAC) );
CORg( g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(pData + dwBufferEnd), dwBytesRead) );
CORg( g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(&dwBytesRead), sizeof(dwBytesRead)) );
CORg( g_pAppSCServer->MACFinal(hMAC, abMACVerify) );
if (memcmp(abMACVerify, abMAC, WMDM_MAC_LENGTH) != 0)
{
hr = WMDM_E_MAC_CHECK_FAILED;
goto exit;
}
}
}
dwBytesRead += dwBufferEnd;
if (hr == S_OK)
{
fUseSCP = TRUE;
if( pSecExch == NULL ) CORg(E_FAIL);
break;
}
else
{
// If the SCP returns S_FALSE then we don't have rights to do the transfer
hr = WMDM_E_NORIGHTS;
goto exit;
}
}
pSecQuery->Release();
pSecQuery = NULL;
}
if (!fUseSCP)
{
CORg( pStgGlobals->GetDevice(&pDevice) );
CORg( pDevice->GetType(&dwType) );
// Do not allow content without and SCP to be transferred to an SDMI only device.
if ((dwType & WMDM_DEVICE_TYPE_SDMI) && (!(dwType & WMDM_DEVICE_TYPE_NONSDMI)))
{
hr = WMDM_E_NORIGHTS;
goto exit;
}
qwFileSizeDest = qwFileSizeSource;
}
// Create the storage to write to.
{
hr = m_pStorage->QueryInterface( __uuidof(IMDSPStorage2), reinterpret_cast<void**>(&pStorage2) );
if( SUCCEEDED(hr) && pStorage2 )
{
hr = pStorage2->CreateStorage2( uNewStorageMode, 0, NULL, NULL, wszNewStorageName, qwFileSizeDest, &pNewSPStorage);
if( hr == E_NOTIMPL )
{
CORg( m_pStorage->CreateStorage(uNewStorageMode, NULL, wszNewStorageName, &pNewSPStorage) );
}
else CORg( hr );
}
else CORg( m_pStorage->CreateStorage(uNewStorageMode, NULL, wszNewStorageName, &pNewSPStorage) );
}
CORg( CComObject<CWMDMStorage>::CreateInstance(&pNewWMDMStorage) );
hr = pNewWMDMStorage->QueryInterface(IID_IWMDMStorage, reinterpret_cast<void**>(&pNewIWMDMStorage));
if (FAILED(hr))
{
delete pNewWMDMStorage;
goto exit;
}
pNewWMDMStorage->SetContainedPointer(pNewSPStorage, m_wSPIndex);
CORg( pNewSPStorage->QueryInterface(IID_IMDSPObject, reinterpret_cast<void **>(&pObject)) );
CORg( pObject->Open(MDSP_WRITE) );
fOpen = TRUE;
// If we are reporting progress then we need to tell the app how many ticks we think there will be
if (pProgress)
{
fBeginCalled = TRUE;
CORg( pProgress->Begin((DWORD)qwFileSizeSource) );
}
fUsedSCP = fUseSCP;
// Copy file
while( !bEOF || bFlushSCP )
{
dwBytesWrite = dwBytesRead;
fuReadyFlags = 0;
// Pass file-data to the SCP
if (fUseSCP && dwBytesRead > 0)
{
CORg( pSCClient->MACInit(&hMAC) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(pData), dwBytesRead) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwBytesRead), sizeof(dwBytesRead)) );
CORg( pSCClient->MACFinal(hMAC, abMAC) );
CORg( pSCClient->EncryptParam(pData, dwBytesRead) );
CORg( pSecExch->TransferContainerData(pData, dwBytesRead, &fuReadyFlags, abMAC) );
CORg( pSCClient->MACInit(&hMAC) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&fuReadyFlags), sizeof(fuReadyFlags)) );
CORg( pSCClient->MACFinal(hMAC, abMACVerify) );
if (memcmp(abMACVerify, abMAC, WMDM_MAC_LENGTH) != 0)
{
hr = WMDM_E_MAC_CHECK_FAILED;
goto exit;
}
// Are we done passing data to the SCP?
bFlushSCP = ((fuReadyFlags & WMDM_SCP_TRANSFER_OBJECTDATA) &&
(fuReadyFlags & WMDM_SCP_NO_MORE_CHANGES))
? TRUE : FALSE;
// The SCP was not interesed in this data, use original data from the file.
if( (fuReadyFlags & WMDM_SCP_NO_MORE_CHANGES) &&
!(fuReadyFlags & WMDM_SCP_TRANSFER_OBJECTDATA) )
{
// Decrypt the original file data
CORg( pSCClient->DecryptParam(pData, dwBytesRead) );
fUseSCP = FALSE;
}
}
// Get data back from SCP
if( fUseSCP && (( fuReadyFlags & WMDM_SCP_TRANSFER_OBJECTDATA) || bFlushSCP ))
{
dwBytesWrite = dwBufferSize;
// Calculate the MAC to send to the SCP
CORg( pSCClient->MACInit(&hMAC) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwBytesWrite), sizeof(dwBytesWrite)) );
CORg( pSCClient->MACFinal(hMAC, abMAC) );
// Get and decrypt data from SCP
CORg( pSecExch->ObjectData(pData, &dwBytesWrite, abMAC) );
if(dwBytesWrite == 0)
{
if( bFlushSCP )
{
bFlushSCP = FALSE;
fUseSCP = FALSE; // Done using the SCP
}
continue;
}
// Decrypt the pData Parameter
CORg( pSCClient->DecryptParam(pData, dwBytesWrite) );
CORg( pSCClient->MACInit(&hMAC) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(pData), dwBytesWrite) );
CORg( pSCClient->MACUpdate(hMAC, (BYTE*)(&dwBytesWrite), sizeof(dwBytesWrite)) );
CORg( pSCClient->MACFinal(hMAC, abMACVerify) );
if (memcmp(abMACVerify, abMAC, WMDM_MAC_LENGTH) != 0)
{
hr = WMDM_E_MAC_CHECK_FAILED;
goto exit;
}
}
// Write data to SP
if ( ((!fUseSCP) || (fuReadyFlags & WMDM_SCP_TRANSFER_OBJECTDATA) || bFlushSCP )
&& dwBytesWrite > 0 )
{
// Create MAC to send to SP
CORg( pSPClient->MACInit(&hMAC) );
CORg( pSPClient->MACUpdate(hMAC, (BYTE*)(pData), dwBytesWrite) );
CORg( pSPClient->MACUpdate(hMAC, (BYTE*)(&dwBytesWrite), sizeof(dwBytesWrite)) );
CORg( pSPClient->MACFinal(hMAC, abMAC) );
CORg( pSPClient->EncryptParam(pData, dwBytesWrite) );
CORg( pObject->Write(pData, &dwBytesWrite, abMAC) );
if (pProgress)
{
dwTicks += dwBytesRead;
CORg( pProgress->Progress(dwTicks) );
}
}
// No valid file data to send to SCP.
dwBytesRead = 0;
// Read new file data
if( !bEOF && !bFlushSCP )
{
dwBytesRead = dwBufferSize;
CORg( g_pAppSCServer->MACInit(&hMAC) );
CORg( g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(pData), dwBytesRead) );
CORg( g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(&dwBytesRead), sizeof(dwBytesRead)) );
CORg( g_pAppSCServer->MACFinal(hMAC, abMAC) );
CORg( g_pAppSCServer->EncryptParam(pData, dwBytesRead) );
CORg( pOperation->TransferObjectData(pData, &dwBytesRead, abMAC) );
bEOF = (S_FALSE == hr) || (dwBytesRead == 0);
bFlushSCP = bEOF && fUseSCP;
if ((S_FALSE == hr) || (dwBytesRead == 0))
{
// If they app returns S_FALSE then there is no more data to transfer
hr = S_OK;
continue;
}
CORg( g_pAppSCServer->DecryptParam(pData, dwBytesRead) );
CORg( g_pAppSCServer->MACInit(&hMAC) );
CORg( g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(pData), dwBytesRead) );
CORg( g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(&dwBytesRead), sizeof(dwBytesRead)) );
CORg( g_pAppSCServer->MACFinal(hMAC, abMACVerify) );
if (memcmp(abMACVerify, abMAC, WMDM_MAC_LENGTH) != 0)
{
CORg( WMDM_E_MAC_CHECK_FAILED );
}
}
} // Copy file
// Close content file
if (pObject && fOpen)
{
HRESULT hr2 = pObject->Close();
hr = FAILED(hr)?hr:hr2;
fOpen = FALSE;
}
// SCP::TransferComplete()
if (fUsedSCP)
{
CORg( pSecExch->TransferComplete() );
}
Error:
exit:
if (pObject && fOpen)
{
HRESULT hr2 = pObject->Close();
hr = FAILED(hr)?hr:hr2;
}
// Delete new storage file if the copy operation failed.
if( FAILED(hr) && pObject )
{
pObject->Delete(0, NULL);
}
if (pProgress)
{
if (!fBeginCalled)
{
pProgress->Begin(1);
}
// pProgress->End(); This is done by the caller
}
SAFE_ARRAY_DELETE(pAppAppCert);
SAFE_ARRAY_DELETE(pSPAppCert);
SAFE_ARRAY_DELETE(pTempData);
SAFE_ARRAY_DELETE(pData);
SAFE_ARRAY_DELETE(pwszFileExt);
// SAFE_ARRAY_DELETE(pwszFileName);
SAFE_RELEASE(pDevice);
SAFE_RELEASE(pStorage2);
SAFE_RELEASE(pStgGlobals);
SAFE_RELEASE(pObject);
SAFE_RELEASE(pSecureAuth);
SAFE_RELEASE(pSecQuery);
SAFE_RELEASE(pSecQuery2);
SAFE_RELEASE(pSecExch);
SAFE_RELEASE(pNewSPStorage);
hrLogDWORD("CWMDMStorage::hrCopyToStorageFromOperation returned 0x%08lx", hr, hr);
return hr;
}
HRESULT CWMDMStorage::hrCopyToFileFromStorage(LPWSTR pwszFileName, IWMDMProgress *pProgress, IMDSPObject *pObject)
{
USES_CONVERSION;
HRESULT hr;
HANDLE hFile = INVALID_HANDLE_VALUE;
BYTE *pData = NULL;
DWORD dwBytes;
DWORD dwBytesWritten;
DWORD dwTotalBytes = 0;
HMAC hMAC;
BYTE abMAC[WMDM_MAC_LENGTH];
BYTE abMACVerify[WMDM_MAC_LENGTH];
CSecureChannelClient *pSPClient = NULL;
BOOL fOpen = FALSE;
DWORD dwVersion;
pData = new BYTE[WMDM_TRANSFER_BUFFER_SIZE];
if (!pData)
{
hr = E_OUTOFMEMORY;
goto exit;
}
dwVersion = GetVersion();
if (dwVersion < 0x80000000)
{
hFile = CreateFileW(pwszFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
}
else
{
hFile = CreateFileA(W2A(pwszFileName), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
}
if (hFile == INVALID_HANDLE_VALUE)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto exit;
}
CORg( pObject->Open(MDSP_READ) );
fOpen = TRUE;
g_pSPs[m_wSPIndex]->GetSCClient(&pSPClient);
if (!pSPClient)
{
hr = E_FAIL;
goto exit;
}
dwBytesWritten = WMDM_TRANSFER_BUFFER_SIZE;
while ((WMDM_TRANSFER_BUFFER_SIZE == dwBytesWritten))
{
dwBytes = WMDM_TRANSFER_BUFFER_SIZE;
CORg( pObject->Read(pData, &dwBytes, abMAC) );
CORg( pSPClient->DecryptParam(pData, dwBytes) );
// Verify MAC returned by SP
CORg( pSPClient->MACInit(&hMAC) );
CORg( pSPClient->MACUpdate(hMAC, (BYTE*)(pData), dwBytes) );
CORg( pSPClient->MACUpdate(hMAC, (BYTE*)(&dwBytes), sizeof(dwBytes)) );
CORg( pSPClient->MACFinal(hMAC, abMACVerify) );
if (memcmp(abMACVerify, abMAC, WMDM_MAC_LENGTH) != 0)
{
hr = WMDM_E_MAC_CHECK_FAILED;
goto exit;
}
CFRg( WriteFile(hFile, pData, dwBytes, &dwBytesWritten, NULL) );
dwTotalBytes+=dwBytesWritten;
if (pProgress)
{
CORg( pProgress->Progress(dwTotalBytes) );
}
}
exit:
Error:
if (hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
}
if (pObject && fOpen)
{
HRESULT hr2 = pObject->Close();
hr = FAILED(hr)?hr:hr2;
}
SAFE_ARRAY_DELETE(pData);
hrLogDWORD("CWMDMStorage::hrCopyToFileFromStorage returned 0x%08lx", hr, hr);
return hr;
}
DWORD InsertThreadFunc(void *pData)
{
INSERTTHREADARGS *pThreadArgs = NULL;
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (SUCCEEDED(hr))
{
pThreadArgs = (INSERTTHREADARGS *)pData;
// We need to marshal the interfaces that the application passes down to us.
// These interfaces can come from an STA and we will make callabacks on them.
IWMDMOperation *pOperation = NULL;
IWMDMProgress *pProgress = NULL;
IUnknown *pUnknown = NULL;
if( pThreadArgs->pOperationStream )
{
hr = CoGetInterfaceAndReleaseStream( pThreadArgs->pOperationStream,
__uuidof(IWMDMOperation),
(void**)&pOperation );
}
if (SUCCEEDED(hr) && pThreadArgs->pProgressStream )
{
hr = CoGetInterfaceAndReleaseStream( pThreadArgs->pProgressStream,
__uuidof(IWMDMProgress),
(void**)&pProgress );
}
if (SUCCEEDED(hr) && pThreadArgs->pUnknownStream )
{
hr = CoGetInterfaceAndReleaseStream( pThreadArgs->pUnknownStream,
__uuidof(IUnknown),
(void**)&pUnknown );
}
if (SUCCEEDED(hr))
{
hr = ((CWMDMStorage *)(pThreadArgs->pThis))->InsertWorker(pThreadArgs->fuMode,
pThreadArgs->pwszFileSource,
pThreadArgs->pwszFileDest,
pOperation,
pProgress,
pUnknown,
pThreadArgs->ppNewObject);
}
SAFE_RELEASE( pOperation );
SAFE_RELEASE( pProgress );
SAFE_RELEASE( pUnknown );
CoUninitialize();
}
if (pThreadArgs)
{
SAFE_DELETE( pThreadArgs->pwszFileSource);
SAFE_DELETE( pThreadArgs->pwszFileDest);
SAFE_RELEASE( pThreadArgs->pThis );
}
delete pData;
return SUCCEEDED(hr)?0:-1;
}
HRESULT CWMDMStorage::InsertWorker(UINT fuMode,
LPWSTR pwszFileSource,
LPWSTR pwszFileDest,
IWMDMOperation *pOperation,
IWMDMProgress *pProgress,
IUnknown* pUnknown,
IWMDMStorage **ppNewObject)
{
HRESULT hr;
HRESULT hr2;
IMDSPStorage *pNewSPStorage = NULL;
CComObject<CWMDMStorage> *pNewWMDMStorage = NULL;
IWMDMStorage *pNewIWMDMStorage = NULL;
UINT fuNewMode = 0;
WCHAR wszDest[512];
BOOL fQuery;
BOOL fOperation;
DWORD dwAttributes;
BOOL fIsFile;
IMDSPObject *pObject = NULL;
// BUGBUG: Fix this to a normal WAVEFORMATEX
_WAVEFORMATEX Format;
BOOL fBeginCalled = FALSE;
// Update storage status
m_dwStatus &= WMDM_STATUS_STORAGECONTROL_INSERTING;
fOperation = fuMode & WMDM_CONTENT_OPERATIONINTERFACE;
fIsFile = fuMode & WMDM_CONTENT_FILE;
fuNewMode = fuMode & (WMDM_STORAGECONTROL_INSERTINTO | WMDM_STORAGECONTROL_INSERTAFTER | WMDM_STORAGECONTROL_INSERTBEFORE);
if ((fOperation) && (!pOperation))
{
hr = E_INVALIDARG;
goto exit;
}
// BUGBUG: Deal with WAVEFORMATEX
if (!fOperation)
{
if (!pwszFileSource)
{
hr = E_INVALIDARG;
goto exit;
}
// Get output file name
if( pwszFileDest != NULL )
{
// Use name passed in
wcsncpy(wszDest, pwszFileDest, sizeof(wszDest)/sizeof(wszDest[0]));
}
else
{
// Use same as source name
if (NULL != wcschr(pwszFileSource, L'\\'))
{
// Copy source name from last '\'
wcsncpy(wszDest, (LPWSTR)(wcsrchr(pwszFileSource, L'\\') + 1), sizeof(wszDest)/sizeof(wszDest[0]) );
}
else
{
wcsncpy(wszDest, pwszFileSource, sizeof(wszDest)/sizeof(wszDest[0]) );
}
}
if (fuMode & WMDM_CONTENT_FILE)
{
fuNewMode |= WMDM_FILE_ATTR_FILE;
}
else if (fuMode & WMDM_CONTENT_FOLDER)
{
fuNewMode |= WMDM_FILE_ATTR_FOLDER;
}
else
{
hr = E_INVALIDARG;
goto exit;
}
if (fuMode & WMDM_FILE_CREATE_OVERWRITE)
{
fuNewMode |= WMDM_FILE_CREATE_OVERWRITE;
}
}
else
{
CORg( pOperation->BeginWrite() );
if( pwszFileDest != NULL )
{
// Use name passed in
wcsncpy(wszDest, pwszFileDest, sizeof(wszDest)/sizeof(wszDest[0]) );
}
else
{
CORg( pOperation->GetObjectName(wszDest, 512) );
}
CORg( pOperation->GetObjectAttributes(&dwAttributes, &Format) );
fIsFile = dwAttributes & WMDM_FILE_ATTR_FILE;
fuNewMode |= dwAttributes;
}
fQuery = fuMode & WMDM_MODE_QUERY;
if (fIsFile)
{
if (fOperation)
{
fBeginCalled = TRUE;
hr = hrCopyToStorageFromOperation(fuMode, pOperation,
fuNewMode, wszDest,
pNewIWMDMStorage,
pProgress, pUnknown,
fQuery);
CORg( hr );
}
else
{
fBeginCalled = TRUE;
hr = hrCopyToStorageFromFile(fuMode, pwszFileSource,
fuNewMode, wszDest,
pNewIWMDMStorage,
pProgress, pUnknown,
fQuery);
CORg( hr );
}
}
else
{
// Create the folder
CORg( m_pStorage->CreateStorage(fuNewMode, NULL, wszDest, &pNewSPStorage) );
CORg( CComObject<CWMDMStorage>::CreateInstance(&pNewWMDMStorage) );
CORg( pNewWMDMStorage->QueryInterface(IID_IWMDMStorage, reinterpret_cast<void**>(&pNewIWMDMStorage)) );
pNewWMDMStorage->SetContainedPointer(pNewSPStorage, m_wSPIndex);
}
exit:
Error:
if (SUCCEEDED(hr) && ppNewObject && pNewIWMDMStorage)
{
// If they gave us a pointer then they want the new storage pointer back
*ppNewObject = pNewIWMDMStorage;
(*ppNewObject)->AddRef();
}
else if(ppNewObject) *ppNewObject = NULL;
if( FAILED(hr) )
{
SAFE_RELEASE( pNewSPStorage );
SAFE_DELETE( pNewWMDMStorage );
}
SAFE_RELEASE( pNewIWMDMStorage );
if (fOperation)
{
if (FAILED(hr))
{
pOperation->End(&hr, NULL);
}
else
{
if (pNewIWMDMStorage)
{
pNewIWMDMStorage->AddRef();
}
pOperation->End(&hr, ppNewObject?*ppNewObject:NULL);
}
}
if (pProgress)
{
hr2 = S_OK;
if (!fBeginCalled)
{
hr2 = pProgress->Begin(1);
}
if (SUCCEEDED(hr2))
{
IWMDMProgress2 *pProgress2 = NULL;
HRESULT hrQI;
// Try to use End2 of IWMDMProgress2 interface to report error code back to caller.
hrQI = pProgress->QueryInterface( IID_IWMDMProgress2, (void**)(&pProgress2) );
if( hrQI == S_OK && pProgress2 != NULL )
{
pProgress2->End2(hr);
SAFE_RELEASE( pProgress2 );
}
else
{
pProgress->End();
}
}
}
SAFE_RELEASE(pObject);
// Update storage status
m_dwStatus &= !WMDM_STATUS_STORAGECONTROL_INSERTING;
hrLogDWORD("CWMDMStorage::InsertWorker returned 0x%08lx", hr, hr);
return hr;
}
DWORD DeleteThreadFunc(void *pData)
{
DELETETHREADARGS *pThreadArgs = NULL;
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (SUCCEEDED(hr))
{
IWMDMProgress* pProgress = NULL;
pThreadArgs = (DELETETHREADARGS *)pData;
if( pThreadArgs->pProgressStream )
{
hr = CoGetInterfaceAndReleaseStream( pThreadArgs->pProgressStream,
__uuidof(IWMDMProgress),
(void**)&pProgress );
}
hr = ((CWMDMStorage *)(pThreadArgs->pThis))->DeleteWorker( pThreadArgs->fuMode,
pProgress );
SAFE_RELEASE( pProgress );
CoUninitialize();
}
if (pThreadArgs)
{
SAFE_RELEASE( pThreadArgs->pThis );
}
delete pData;
return SUCCEEDED(hr)?0:-1;
}
HRESULT CWMDMStorage::DeleteWorker(UINT fuMode, IWMDMProgress *pProgress)
{
HRESULT hr;
IMDSPObject *pObject = NULL;
// Update storage status
m_dwStatus &= WMDM_STATUS_STORAGECONTROL_DELETING;
hr = m_pStorage->QueryInterface(IID_IMDSPObject, reinterpret_cast<void**>(&pObject));
if (FAILED(hr))
{
goto exit;
}
hr = pObject->Delete(fuMode, pProgress);
if (FAILED(hr))
{
goto exit;
}
exit:
if (pObject)
pObject->Release();
// Update storage status
m_dwStatus &= !WMDM_STATUS_STORAGECONTROL_DELETING;
hrLogDWORD("CWMDMStorage::DeleteWorker returned 0x%08lx", hr, hr);
return hr;
}
DWORD RenameThreadFunc(void *pData)
{
RENAMETHREADARGS *pThreadArgs = NULL;
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (SUCCEEDED(hr))
{
IWMDMProgress* pProgress = NULL;
pThreadArgs = (RENAMETHREADARGS *)pData;
if( pThreadArgs->pProgressStream )
{
hr = CoGetInterfaceAndReleaseStream( pThreadArgs->pProgressStream,
__uuidof(IWMDMProgress),
(void**)&pProgress );
}
hr = ((CWMDMStorage *)(pThreadArgs->pThis))->RenameWorker(pThreadArgs->pwszNewName,
pProgress );
SAFE_RELEASE( pProgress );
CoUninitialize();
}
if (pThreadArgs)
{
if (pThreadArgs->pwszNewName)
delete pThreadArgs->pwszNewName;
SAFE_RELEASE( pThreadArgs->pThis );
}
delete pData;
return SUCCEEDED(hr)?0:-1;
}
HRESULT CWMDMStorage::RenameWorker(LPWSTR pwszNewName,
IWMDMProgress *pProgress)
{
HRESULT hr;
IMDSPObject *pObject = NULL;
if ((!pwszNewName) || (wcslen(pwszNewName) == 0))
{
hr = E_INVALIDARG;
goto exit;
}
hr = m_pStorage->QueryInterface(IID_IMDSPObject, reinterpret_cast<void**>(&pObject));
if (SUCCEEDED(hr))
{
hr = pObject->Rename(pwszNewName, pProgress);
pObject->Release();
}
exit:
hrLogDWORD("CWMDMStorage::RenameWorker returned 0x%08lx", hr, hr);
return hr;
}
DWORD ReadThreadFunc(void *pData)
{
READTHREADARGS *pThreadArgs = NULL;
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (SUCCEEDED(hr))
{
IWMDMOperation* pOperation = NULL;
IWMDMProgress* pProgress = NULL;
pThreadArgs = (READTHREADARGS *)pData;
if( pThreadArgs->pOperationStream )
{
hr = CoGetInterfaceAndReleaseStream( pThreadArgs->pOperationStream,
__uuidof(IWMDMOperation),
(void**)&pOperation );
}
if (SUCCEEDED(hr) && pThreadArgs->pProgressStream )
{
hr = CoGetInterfaceAndReleaseStream( pThreadArgs->pProgressStream,
__uuidof(IWMDMProgress),
(void**)&pProgress );
}
hr = ((CWMDMStorage *)(pThreadArgs->pThis))->ReadWorker(pThreadArgs->fuMode,
pThreadArgs->pwszFile,
pProgress,
pOperation);
SAFE_RELEASE(pOperation);
SAFE_RELEASE(pProgress);
CoUninitialize();
}
if (pThreadArgs)
{
if (pThreadArgs->pwszFile)
delete pThreadArgs->pwszFile;
SAFE_RELEASE( pThreadArgs->pThis );
}
delete pData;
return SUCCEEDED(hr)?0:-1;
}
HRESULT CWMDMStorage::ReadWorker(UINT fuMode,
LPWSTR pwszFile,
IWMDMProgress *pProgress,
IWMDMOperation *pOperation)
{
HRESULT hr;
IMDSPObject *pObject = NULL;
DWORD dwFileSize;
DWORD dwFileSizeHigh;
BOOL fBeginCalled = FALSE;
// Update Storage status
m_dwStatus &= WMDM_STATUS_STORAGECONTROL_READING;
hr = m_pStorage->GetSize(&dwFileSize, &dwFileSizeHigh);
if (FAILED(hr))
{
goto exit;
}
if (pProgress)
{
hr = pProgress->Begin(dwFileSize);
fBeginCalled = TRUE;
if (FAILED(hr))
{
goto exit;
}
}
hr = m_pStorage->QueryInterface(IID_IMDSPObject, reinterpret_cast<void**>(&pObject));
if (FAILED(hr))
{
goto exit;
}
if (fuMode & WMDM_CONTENT_OPERATIONINTERFACE)
{
if (!pOperation)
{
hr = E_INVALIDARG;
goto exit;
}
hr = hrCopyToOperationFromStorage(pOperation, pProgress, pObject);
if (FAILED(hr))
{
goto exit;
}
}
else
{
if (!pwszFile)
{
hr = E_INVALIDARG;
goto exit;
}
hr = hrCopyToFileFromStorage(pwszFile, pProgress, pObject);
if (FAILED(hr))
{
goto exit;
}
}
exit:
if (pObject)
pObject->Release();
if (pProgress)
{
IWMDMProgress2 *pProgress2 = NULL;
HRESULT hrQI;
if (!fBeginCalled)
{
pProgress->Begin(1);
}
// Try to use End2 of IWMDMProgress2 interface to report error code back to caller.
hrQI = pProgress->QueryInterface( IID_IWMDMProgress2, (void**)(&pProgress2) );
if( hrQI == S_OK && pProgress2 != NULL )
{
pProgress2->End2(hr);
SAFE_RELEASE( pProgress2 );
}
else
{
pProgress->End();
}
}
// Update Storage status
m_dwStatus &= !WMDM_STATUS_STORAGECONTROL_READING;
hrLogDWORD("CWMDMStorage::ReadWorker returned 0x%08lx", hr, hr);
return hr;
}
// IWMDMRevoked
HRESULT CWMDMStorage::GetRevocationURL( LPWSTR* ppwszRevocationURL,
DWORD* pdwBufferLen,
OUT DWORD* pdwRevokedBitFlag )
{
HRESULT hr = S_OK;
CARg( ppwszRevocationURL );
CARg( pdwBufferLen );
CARg( pdwRevokedBitFlag );
// Is the buffer passed in big enough?
if( *pdwBufferLen < wcslen( m_pwszRevocationURL ) || *ppwszRevocationURL == NULL )
{
// Allocate new buffer
*pdwBufferLen = wcslen( m_pwszRevocationURL ) + 1;
CoTaskMemFree( *ppwszRevocationURL );
*ppwszRevocationURL = (LPWSTR)CoTaskMemAlloc( *pdwBufferLen * sizeof(WCHAR) );
if( *ppwszRevocationURL == NULL )
{
hr = E_OUTOFMEMORY;
goto Error;
}
}
wcscpy( *ppwszRevocationURL, m_pwszRevocationURL );
*pdwRevokedBitFlag = m_dwRevocationBitFlag;
Error:
return hr;
}
// We might change the URL given to us by the SCP if the WMDM client or the SP is revoked
HRESULT CWMDMStorage::UpdateRevocationURL( IN OUT LPWSTR* ppwszRevocationURL,
IN OUT DWORD* pdwBufferLen,
IN DWORD* pdwRevocationBitFlag )
{
HRESULT hr = S_OK;
IMDServiceProvider* pSP = NULL;
IMDSPRevoked* pIMDSPRevoked = NULL;
BOOL bUpdateOK = FALSE;
LPWSTR pszTempURL;
DWORD dwTempLen = *pdwBufferLen;
// Work with a temp url so that we don't destroy a good url if something fails
pszTempURL = (LPWSTR)CoTaskMemAlloc( *pdwBufferLen * sizeof(WCHAR) );
CPRg( pszTempURL );
wcscpy( pszTempURL, *ppwszRevocationURL );
// If the SP has been revoked give it a chance to specify an URL of it's own.
if( *pdwRevocationBitFlag & WMDM_SP_REVOKED )
{
CORg( g_pSPs[m_wSPIndex]->hrGetInterface(&pSP) );
hr = pSP->QueryInterface( IID_IMDSPRevoked, (void**)&pIMDSPRevoked );
if( SUCCEEDED(hr) && pIMDSPRevoked )
{
hr = pIMDSPRevoked->GetRevocationURL( &pszTempURL, &dwTempLen );
if( hr != S_OK)
{
// We failed to update the string, reset it to initial value
dwTempLen = *pdwBufferLen;
CoTaskMemFree( pszTempURL );
pszTempURL = (LPWSTR)CoTaskMemAlloc( *pdwBufferLen * sizeof(WCHAR) );
CPRg( pszTempURL );
wcscpy( pszTempURL, *ppwszRevocationURL );
}
else
{
bUpdateOK = TRUE;
}
}
}
// If the WMDM client is revoked we should go to the MS update URL
if( (*pdwRevocationBitFlag & WMDM_WMDM_REVOKED) &&
::IsMicrosoftRevocationURL(pszTempURL) == FALSE )
{
DWORD pdwSubjectIDs[2];
pdwSubjectIDs[0] = ::GetSubjectIDFromAppCert( *(APPCERT*)g_abAppCert );
pdwSubjectIDs[1] = 0;
hr = ::BuildRevocationURL( pdwSubjectIDs, &pszTempURL, &dwTempLen );
if(hr == S_OK)
{
bUpdateOK = TRUE;
}
}
// URL has changed, update out param.
if( bUpdateOK && wcscmp( pszTempURL, *ppwszRevocationURL ) != 0 )
{
*pdwBufferLen = dwTempLen;
CoTaskMemFree( *ppwszRevocationURL );
*ppwszRevocationURL = (LPWSTR)CoTaskMemAlloc( dwTempLen * sizeof(WCHAR) );
CPRg( *ppwszRevocationURL );
wcscpy( *ppwszRevocationURL, pszTempURL );
}
Error:
if( pszTempURL != NULL )
{
CoTaskMemFree( pszTempURL );
}
SAFE_RELEASE(pSP);
SAFE_RELEASE(pIMDSPRevoked);
return hr;
}