// 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 //#define DUMP_FILE #ifdef DUMP_FILE #include #include #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 *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::CreateInstance(&pStgGlobal) ); hr = pStgGlobal->QueryInterface(IID_IWMDMStorageGlobals, reinterpret_cast(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(&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 *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::CreateInstance(&pEnumObj) ); hr = pEnumObj->QueryInterface(IID_IWMDMEnumStorage, reinterpret_cast(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* 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(&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::CreateInstance(&pStgObj) ); CORg( pStgObj->QueryInterface(IID_IWMDMStorage, reinterpret_cast(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(&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(&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 *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(&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(&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(&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(&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(&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(&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(&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(&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 *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(&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::CreateInstance(&pNewWMDMStorage) ); hr = pNewWMDMStorage->QueryInterface(IID_IWMDMStorage, reinterpret_cast(&pNewIWMDMStorage)); if (FAILED(hr)) { delete pNewWMDMStorage; goto exit; } pNewWMDMStorage->SetContainedPointer(pNewSPStorage, m_wSPIndex); CORg( pNewSPStorage->QueryInterface(IID_IMDSPObject, reinterpret_cast(&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 *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(&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::CreateInstance(&pNewWMDMStorage) ); hr = pNewWMDMStorage->QueryInterface(IID_IWMDMStorage, reinterpret_cast(&pNewIWMDMStorage)); if (FAILED(hr)) { delete pNewWMDMStorage; goto exit; } pNewWMDMStorage->SetContainedPointer(pNewSPStorage, m_wSPIndex); CORg( pNewSPStorage->QueryInterface(IID_IMDSPObject, reinterpret_cast(&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 *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::CreateInstance(&pNewWMDMStorage) ); CORg( pNewWMDMStorage->QueryInterface(IID_IWMDMStorage, reinterpret_cast(&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(&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(&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(&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; }