Changeset 54486 in vbox
- Timestamp:
- Feb 25, 2015 12:49:39 PM (10 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/idl/VirtualBox.xidl
r54438 r54486 13417 13417 <interface 13418 13418 name="IMedium" extends="$unknown" 13419 uuid=" 05f2bbb6-a3a6-4fb9-9b49-6d0dda7142ac"13419 uuid="e6aa3c67-6f51-4ba6-a012-cf4825069abb" 13420 13420 wsmap="managed" 13421 13421 > … … 14660 14660 </result> 14661 14661 </desc> 14662 <param name="progress" type="IProgress" dir="return"> 14663 <desc>Progress object to track the operation completion.</desc> 14664 </param> 14665 </method> 14666 14667 <method name="changeEncryption"> 14668 <desc> 14669 Starts encryption of this medium. This means that the stored data in the 14670 medium is encrypted. 14671 14672 This medium will be placed to <link to="MediumState_LockedWrite"/> 14673 state. 14674 14675 Please note that the results can be either returned straight away, 14676 or later as the result of the background operation via the object 14677 returned via the @a progress parameter. 14678 14679 <result name="VBOX_E_NOT_SUPPORTED"> 14680 Encryption is not supported for this medium because it is attached to more than one VM 14681 or has children. 14682 </result> 14683 </desc> 14684 <param name="newPassword" type="wstring" dir="in"> 14685 <desc> 14686 The new password the medium should be protected with. Use an empty string 14687 to indicate that the result should not be encrypted. 14688 </desc> 14689 </param> 14690 <param name="oldPassword" type="wstring" dir="in"> 14691 <desc> 14692 The old password the medium is protected with. Use an empty string to indicate 14693 that the medium wasn't encrypted before. 14694 </desc> 14695 </param> 14696 <param name="cipher" type="wstring" dir="in"> 14697 <desc>The cipher to use for encryption.</desc> 14698 </param> 14662 14699 <param name="progress" type="IProgress" dir="return"> 14663 14700 <desc>Progress object to track the operation completion.</desc> -
trunk/src/VBox/Main/include/MediumImpl.h
r53541 r54486 275 275 ComPtr<IProgress> &aProgress); 276 276 HRESULT reset(ComPtr<IProgress> &aProgress); 277 HRESULT changeEncryption(const com::Utf8Str &aNewPassword, const com::Utf8Str &aOldPassword, 278 const com::Utf8Str &aCipher, ComPtr<IProgress> &aProgress); 277 279 278 280 // Private internal nmethods … … 312 314 static DECLCALLBACK(int) i_vdTcpGetPeerAddress(VDSOCKET Sock, PRTNETADDR pAddr); 313 315 316 static DECLCALLBACK(bool) i_vdCryptoConfigAreKeysValid(void *pvUser, 317 const char *pszzValid); 318 static DECLCALLBACK(int) i_vdCryptoConfigQuerySize(void *pvUser, const char *pszName, 319 size_t *pcbValue); 320 static DECLCALLBACK(int) i_vdCryptoConfigQuery(void *pvUser, const char *pszName, 321 char *pszValue, size_t cchValue); 322 323 static DECLCALLBACK(int) i_vdCryptoKeyRetain(void *pvUser, const char *pszId, 324 const uint8_t **ppbKey, size_t *pcbKey); 325 static DECLCALLBACK(int) i_vdCryptoKeyRelease(void *pvUser, const char *pszId); 326 static DECLCALLBACK(int) i_vdCryptoKeyStoreGetPassword(void *pvUser, const char **ppszPassword); 327 static DECLCALLBACK(int) i_vdCryptoKeyStoreSave(void *pvUser, const void *pvKeyStore, size_t cbKeyStore); 328 static DECLCALLBACK(int) i_vdCryptoKeyStoreReturnParameters(void *pvUser, const char *pszCipher, 329 const uint8_t *pbDek, size_t cbDek); 330 314 331 class Task; 315 332 class CreateBaseTask; … … 323 340 class ExportTask; 324 341 class ImportTask; 342 class EncryptTask; 325 343 friend class Task; 326 344 friend class CreateBaseTask; … … 334 352 friend class ExportTask; 335 353 friend class ImportTask; 354 friend class EncryptTask; 336 355 337 356 HRESULT i_startThread(Medium::Task *pTask); … … 348 367 HRESULT i_taskExportHandler(Medium::ExportTask &task); 349 368 HRESULT i_taskImportHandler(Medium::ImportTask &task); 369 HRESULT i_taskEncryptHandler(Medium::EncryptTask &task); 370 371 struct CryptoFilterSettings; 372 void i_taskEncryptSettingsSetup(CryptoFilterSettings *pSettings, const char *pszCipher, 373 const char *pszKeyStore, const char *pszPassword, 374 bool fCreateKeyStore); 350 375 351 376 struct Data; // opaque data struct, defined in MediumImpl.cpp -
trunk/src/VBox/Main/src-server/MediumImpl.cpp
r54438 r54486 20 20 #include "SystemPropertiesImpl.h" 21 21 #include "VirtualBoxImpl.h" 22 #include "ExtPackManagerImpl.h" 22 23 23 24 #include "AutoCaller.h" … … 35 36 #include <iprt/tcp.h> 36 37 #include <iprt/cpp/utils.h> 38 #include <iprt/memsafer.h> 39 #include <iprt/base64.h> 37 40 38 41 #include <VBox/vd.h> … … 40 43 #include <algorithm> 41 44 #include <list> 45 46 #include <openssl/rand.h> 42 47 43 48 typedef std::list<Guid> GuidList; … … 666 671 }; 667 672 673 class Medium::EncryptTask : public Medium::Task 674 { 675 public: 676 EncryptTask(Medium *aMedium, 677 const com::Utf8Str &strNewPassword, 678 const com::Utf8Str &strOldPassword, 679 const com::Utf8Str &strCipher, 680 Progress *aProgress, 681 MediumLockList *aMediumLockList) 682 : Medium::Task(aMedium, aProgress), 683 mstrNewPassword(strNewPassword), 684 mstrOldPassword(strOldPassword), 685 mstrCipher(strCipher), 686 mpMediumLockList(aMediumLockList) 687 { 688 AssertReturnVoidStmt(aMediumLockList != NULL, mRC = E_FAIL); 689 /* aParent may be NULL */ 690 mRC = mParentCaller.rc(); 691 if (FAILED(mRC)) 692 return; 693 694 mVDImageIfaces = aMedium->m->vdImageIfaces; 695 } 696 697 ~EncryptTask() 698 { 699 if (mstrNewPassword.length()) 700 RTMemWipeThoroughly(mstrNewPassword.mutableRaw(), mstrNewPassword.length(), 10 /* cPasses */); 701 if (mstrOldPassword.length()) 702 RTMemWipeThoroughly(mstrOldPassword.mutableRaw(), mstrOldPassword.length(), 10 /* cPasses */); 703 delete mpMediumLockList; 704 } 705 706 Utf8Str mstrNewPassword; 707 Utf8Str mstrOldPassword; 708 Utf8Str mstrCipher; 709 MediumLockList *mpMediumLockList; 710 PVDINTERFACE mVDImageIfaces; 711 712 private: 713 virtual HRESULT handler(); 714 715 AutoCaller mParentCaller; 716 }; 717 718 /** 719 * Settings for a crypto filter instance. 720 */ 721 struct Medium::CryptoFilterSettings 722 { 723 CryptoFilterSettings() 724 : fCreateKeyStore(false), 725 pszPassword(NULL), 726 pszKeyStore(NULL), 727 pszKeyStoreLoad(NULL), 728 pbDek(NULL), 729 cbDek(0), 730 pszCipher(NULL) 731 { } 732 733 bool fCreateKeyStore; 734 const char *pszPassword; 735 char *pszKeyStore; 736 const char *pszKeyStoreLoad; 737 738 const uint8_t *pbDek; 739 size_t cbDek; 740 const char *pszCipher; 741 742 PVDINTERFACE vdFilterIfaces; 743 744 VDINTERFACECONFIG vdIfCfg; 745 VDINTERFACECRYPTO vdIfCrypto; 746 }; 747 668 748 /** 669 749 * Thread function for time-consuming medium tasks. … … 803 883 { 804 884 return mMedium->i_taskImportHandler(*this); 885 } 886 887 /** 888 * Implementation code for the "encrypt" task. 889 */ 890 HRESULT Medium::EncryptTask::handler() 891 { 892 return mMedium->i_taskEncryptHandler(*this); 805 893 } 806 894 … … 2934 3022 2935 3023 LogFlowThisFunc(("LEAVE, rc=%Rhrc\n", rc)); 3024 3025 return rc; 3026 } 3027 3028 HRESULT Medium::changeEncryption(const com::Utf8Str &aNewPassword, const com::Utf8Str &aOldPassword, 3029 const com::Utf8Str &aCipher, ComPtr<IProgress> &aProgress) 3030 { 3031 HRESULT rc = S_OK; 3032 ComObjPtr<Progress> pProgress; 3033 Medium::Task *pTask = NULL; 3034 3035 try 3036 { 3037 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 3038 3039 DeviceType_T devType = i_getDeviceType(); 3040 /* Cannot encrypt DVD or floppy images so far. */ 3041 if ( devType == DeviceType_DVD 3042 || devType == DeviceType_Floppy) 3043 return setError(VBOX_E_INVALID_OBJECT_STATE, 3044 tr("Cannot encrypt DVD or Floppy medium '%s'"), 3045 m->strLocationFull.c_str()); 3046 3047 /* Cannot encrypt child media so far. */ 3048 if (m->pParent) 3049 return setError(VBOX_E_INVALID_OBJECT_STATE, 3050 tr("Cannot encrypt medium '%s' because it is a differencing medium"), 3051 m->strLocationFull.c_str()); 3052 3053 /* Cannot encrypt media which are attached to more than one virtual machine. */ 3054 if (m->backRefs.size() > 1) 3055 return setError(VBOX_E_INVALID_OBJECT_STATE, 3056 tr("Cannot encrypt medium '%s' because it is attached to %d virtual machines"), 3057 m->strLocationFull.c_str(), m->backRefs.size()); 3058 3059 if (m->llChildren.size() != 0) 3060 return setError(VBOX_E_INVALID_OBJECT_STATE, 3061 tr("Cannot encrypt medium '%s' because it has %d children"), 3062 m->strLocationFull.c_str(), m->llChildren.size()); 3063 3064 /* Build the medium lock list. */ 3065 MediumLockList *pMediumLockList(new MediumLockList()); 3066 alock.release(); 3067 rc = i_createMediumLockList(true /* fFailIfInaccessible */ , 3068 true /* fMediumLockWrite */, 3069 NULL, 3070 *pMediumLockList); 3071 alock.acquire(); 3072 if (FAILED(rc)) 3073 { 3074 delete pMediumLockList; 3075 throw rc; 3076 } 3077 3078 alock.release(); 3079 rc = pMediumLockList->Lock(); 3080 alock.acquire(); 3081 if (FAILED(rc)) 3082 { 3083 delete pMediumLockList; 3084 throw setError(rc, 3085 tr("Failed to lock media when compacting '%s'"), 3086 i_getLocationFull().c_str()); 3087 } 3088 3089 pProgress.createObject(); 3090 rc = pProgress->init(m->pVirtualBox, 3091 static_cast <IMedium *>(this), 3092 BstrFmt(tr("Compacting medium '%s'"), m->strLocationFull.c_str()).raw(), 3093 TRUE /* aCancelable */); 3094 if (FAILED(rc)) 3095 { 3096 delete pMediumLockList; 3097 throw rc; 3098 } 3099 3100 /* setup task object to carry out the operation asynchronously */ 3101 pTask = new Medium::EncryptTask(this, aNewPassword, aOldPassword, 3102 aCipher, pProgress, pMediumLockList); 3103 rc = pTask->rc(); 3104 AssertComRC(rc); 3105 if (FAILED(rc)) 3106 throw rc; 3107 } 3108 catch (HRESULT aRC) { rc = aRC; } 3109 3110 if (SUCCEEDED(rc)) 3111 { 3112 rc = i_startThread(pTask); 3113 3114 if (SUCCEEDED(rc)) 3115 pProgress.queryInterfaceTo(aProgress.asOutParam()); 3116 } 3117 else if (pTask != NULL) 3118 delete pTask; 2936 3119 2937 3120 return rc; … … 6602 6785 PVDSOCKETINT pSocketInt = (PVDSOCKETINT)Sock; 6603 6786 return RTTcpGetPeerAddress(pSocketInt->hSocket, pAddr); 6787 } 6788 6789 DECLCALLBACK(bool) Medium::i_vdCryptoConfigAreKeysValid(void *pvUser, const char *pszzValid) 6790 { 6791 /* Just return always true here. */ 6792 return true; 6793 } 6794 6795 DECLCALLBACK(int) Medium::i_vdCryptoConfigQuerySize(void *pvUser, const char *pszName, size_t *pcbValue) 6796 { 6797 Medium::CryptoFilterSettings *pSettings = (Medium::CryptoFilterSettings *)pvUser; 6798 AssertPtrReturn(pSettings, VERR_GENERAL_FAILURE); 6799 AssertReturn(VALID_PTR(pcbValue), VERR_INVALID_POINTER); 6800 6801 size_t cbValue = 0; 6802 if (!strcmp(pszName, "Algorithm")) 6803 cbValue = strlen(pSettings->pszCipher) + 1; 6804 else if (!strcmp(pszName, "KeyStore")) 6805 cbValue = RTBase64DecodedSize(pSettings->pszKeyStoreLoad, NULL) + 1; 6806 else if (!strcmp(pszName, "CreateKeyStore")) 6807 cbValue = 2; /* Single digit + terminator. */ 6808 else 6809 return VERR_CFGM_VALUE_NOT_FOUND; 6810 6811 *pcbValue = cbValue + 1 /* include terminator */; 6812 6813 return VINF_SUCCESS; 6814 } 6815 6816 DECLCALLBACK(int) Medium::i_vdCryptoConfigQuery(void *pvUser, const char *pszName, 6817 char *pszValue, size_t cchValue) 6818 { 6819 Medium::CryptoFilterSettings *pSettings = (Medium::CryptoFilterSettings *)pvUser; 6820 AssertPtrReturn(pSettings, VERR_GENERAL_FAILURE); 6821 AssertReturn(VALID_PTR(pszValue), VERR_INVALID_POINTER); 6822 6823 if (!strcmp(pszName, "KeyStore")) 6824 return RTBase64Decode(pSettings->pszKeyStoreLoad, pszValue, cchValue, NULL, NULL); 6825 else 6826 { 6827 const char *psz = NULL; 6828 if (!strcmp(pszName, "Algorithm")) 6829 psz = pSettings->pszCipher; 6830 else if (!strcmp(pszName, "CreateKeyStore")) 6831 { 6832 if (pSettings->fCreateKeyStore) 6833 psz = "1"; 6834 else 6835 psz = "0"; 6836 } 6837 else 6838 return VERR_CFGM_VALUE_NOT_FOUND; 6839 6840 size_t cch = strlen(psz); 6841 if (cch >= cchValue) 6842 return VERR_CFGM_NOT_ENOUGH_SPACE; 6843 6844 memcpy(pszValue, psz, cch + 1); 6845 } 6846 6847 return VINF_SUCCESS; 6848 } 6849 6850 DECLCALLBACK(int) Medium::i_vdCryptoKeyRetain(void *pvUser, const char *pszId, 6851 const uint8_t **ppbKey, size_t *pcbKey) 6852 { 6853 Medium::CryptoFilterSettings *pSettings = (Medium::CryptoFilterSettings *)pvUser; 6854 AssertPtrReturn(pSettings, VERR_GENERAL_FAILURE); 6855 AssertMsgFailedReturn(("This method should not be called here!\n"), VERR_INVALID_STATE); 6856 } 6857 6858 DECLCALLBACK(int) Medium::i_vdCryptoKeyRelease(void *pvUser, const char *pszId) 6859 { 6860 Medium::CryptoFilterSettings *pSettings = (Medium::CryptoFilterSettings *)pvUser; 6861 AssertPtrReturn(pSettings, VERR_GENERAL_FAILURE); 6862 AssertMsgFailedReturn(("This method should not be called here!\n"), VERR_INVALID_STATE); 6863 } 6864 6865 DECLCALLBACK(int) Medium::i_vdCryptoKeyStoreGetPassword(void *pvUser, const char **ppszPassword) 6866 { 6867 Medium::CryptoFilterSettings *pSettings = (Medium::CryptoFilterSettings *)pvUser; 6868 AssertPtrReturn(pSettings, VERR_GENERAL_FAILURE); 6869 6870 *ppszPassword = pSettings->pszPassword; 6871 return VINF_SUCCESS; 6872 } 6873 6874 DECLCALLBACK(int) Medium::i_vdCryptoKeyStoreSave(void *pvUser, const void *pvKeyStore, size_t cbKeyStore) 6875 { 6876 Medium::CryptoFilterSettings *pSettings = (Medium::CryptoFilterSettings *)pvUser; 6877 AssertPtrReturn(pSettings, VERR_GENERAL_FAILURE); 6878 6879 size_t cbEnc = RTBase64EncodedLength(cbKeyStore); 6880 pSettings->pszKeyStore = (char *)RTMemAllocZ(cbEnc + 1); 6881 if (!pSettings->pszKeyStore) 6882 return VERR_NO_MEMORY; 6883 6884 int rc = RTBase64Encode(pvKeyStore, cbKeyStore, pSettings->pszKeyStore, cbEnc + 1, NULL); 6885 if (RT_FAILURE(rc)) 6886 { 6887 RTMemFree(pSettings->pszKeyStore); 6888 pSettings->pszKeyStore = NULL; 6889 } 6890 6891 return rc; 6892 } 6893 6894 DECLCALLBACK(int) Medium::i_vdCryptoKeyStoreReturnParameters(void *pvUser, const char *pszCipher, 6895 const uint8_t *pbDek, size_t cbDek) 6896 { 6897 Medium::CryptoFilterSettings *pSettings = (Medium::CryptoFilterSettings *)pvUser; 6898 AssertPtrReturn(pSettings, VERR_GENERAL_FAILURE); 6899 6900 pSettings->pszCipher = pszCipher; 6901 pSettings->pbDek = pbDek; 6902 pSettings->cbDek = cbDek; 6903 6904 return VINF_SUCCESS; 6604 6905 } 6605 6906 … … 8404 8705 } 8405 8706 8707 /** 8708 * Sets up the encryption settings for a filter. 8709 */ 8710 void Medium::i_taskEncryptSettingsSetup(CryptoFilterSettings *pSettings, const char *pszCipher, 8711 const char *pszKeyStore, const char *pszPassword, 8712 bool fCreateKeyStore) 8713 { 8714 pSettings->pszCipher = pszCipher; 8715 pSettings->pszPassword = pszPassword; 8716 pSettings->pszKeyStoreLoad = pszKeyStore; 8717 pSettings->fCreateKeyStore = fCreateKeyStore; 8718 pSettings->pbDek = NULL; 8719 pSettings->cbDek = 0; 8720 pSettings->vdFilterIfaces = NULL; 8721 8722 pSettings->vdIfCfg.pfnAreKeysValid = i_vdCryptoConfigAreKeysValid; 8723 pSettings->vdIfCfg.pfnQuerySize = i_vdCryptoConfigQuerySize; 8724 pSettings->vdIfCfg.pfnQuery = i_vdCryptoConfigQuery; 8725 pSettings->vdIfCfg.pfnQueryBytes = NULL; 8726 8727 pSettings->vdIfCrypto.pfnKeyRetain = i_vdCryptoKeyRetain; 8728 pSettings->vdIfCrypto.pfnKeyRelease = i_vdCryptoKeyRelease; 8729 pSettings->vdIfCrypto.pfnKeyStoreGetPassword = i_vdCryptoKeyStoreGetPassword; 8730 pSettings->vdIfCrypto.pfnKeyStoreSave = i_vdCryptoKeyStoreSave; 8731 pSettings->vdIfCrypto.pfnKeyStoreReturnParameters = i_vdCryptoKeyStoreReturnParameters; 8732 8733 int vrc = VDInterfaceAdd(&pSettings->vdIfCfg.Core, 8734 "Medium::vdInterfaceCfgCrypto", 8735 VDINTERFACETYPE_CONFIG, pSettings, 8736 sizeof(VDINTERFACECONFIG), &pSettings->vdFilterIfaces); 8737 AssertRC(vrc); 8738 8739 vrc = VDInterfaceAdd(&pSettings->vdIfCrypto.Core, 8740 "Medium::vdInterfaceCrypto", 8741 VDINTERFACETYPE_CRYPTO, pSettings, 8742 sizeof(VDINTERFACECRYPTO), &pSettings->vdFilterIfaces); 8743 AssertRC(vrc); 8744 } 8745 8746 /** 8747 * Implementation code for the "compact" task. 8748 * 8749 * @param task 8750 * @return 8751 */ 8752 HRESULT Medium::i_taskEncryptHandler(Medium::EncryptTask &task) 8753 { 8754 HRESULT rc = S_OK; 8755 8756 /* Lock all in {parent,child} order. The lock is also used as a 8757 * signal from the task initiator (which releases it only after 8758 * RTThreadCreate()) that we can start the job. */ 8759 AutoWriteLock thisLock(this COMMA_LOCKVAL_SRC_POS); 8760 8761 try 8762 { 8763 # ifdef VBOX_WITH_EXTPACK 8764 static const Utf8Str strExtPackPuel("Oracle VM VirtualBox Extension Pack"); 8765 static const char *s_pszVDPlugin = "VDPluginCrypt"; 8766 ExtPackManager *pExtPackManager = m->pVirtualBox->i_getExtPackManager(); 8767 if (pExtPackManager->i_isExtPackUsable(strExtPackPuel.c_str())) 8768 { 8769 /* Load the plugin */ 8770 Utf8Str strPlugin; 8771 rc = pExtPackManager->i_getLibraryPathForExtPack(s_pszVDPlugin, &strExtPackPuel, &strPlugin); 8772 if (SUCCEEDED(rc)) 8773 { 8774 int vrc = VDPluginLoadFromFilename(strPlugin.c_str()); 8775 if (RT_FAILURE(vrc)) 8776 throw setError(VBOX_E_NOT_SUPPORTED, 8777 tr("Encrypting the image failed because the encryption plugin could not be loaded (%s)"), 8778 i_vdError(vrc).c_str()); 8779 } 8780 else 8781 throw setError(VBOX_E_NOT_SUPPORTED, 8782 tr("Encryption is not supported because the extension pack '%s' is missing the encryption plugin (old extension pack installed?)"), 8783 strExtPackPuel.c_str()); 8784 } 8785 else 8786 throw setError(VBOX_E_NOT_SUPPORTED, 8787 tr("Encryption is not supported because the extension pack '%s' is missing"), 8788 strExtPackPuel.c_str()); 8789 8790 PVBOXHDD pDisk = NULL; 8791 int vrc = VDCreate(m->vdDiskIfaces, i_convertDeviceType(), &pDisk); 8792 ComAssertRCThrow(vrc, E_FAIL); 8793 8794 Medium::CryptoFilterSettings CryptoSettingsRead; 8795 Medium::CryptoFilterSettings CryptoSettingsWrite; 8796 8797 uint8_t *pbDek = NULL; 8798 size_t cbDek = 0; 8799 char *pszCipherOld = NULL; 8800 char *pszKeyStoreEncNew = NULL; 8801 void *pvBuf = NULL; 8802 try 8803 { 8804 /* Set up disk encryption filters. */ 8805 if (task.mstrOldPassword.isEmpty()) 8806 { 8807 /* 8808 * Query whether the medium property indicating that encryption is 8809 * configured is existing. 8810 */ 8811 settings::StringsMap::iterator it = m->mapProperties.find("CRYPT/KeyStore"); 8812 if (it != m->mapProperties.end()) 8813 throw setError(VBOX_E_INVALID_OBJECT_STATE, 8814 tr("The password given for the encrypted image is incorrect")); 8815 } 8816 else 8817 { 8818 settings::StringsMap::iterator it = m->mapProperties.find("CRYPT/KeyStore"); 8819 if (it == m->mapProperties.end()) 8820 throw setError(VBOX_E_INVALID_OBJECT_STATE, 8821 tr("The image is not configured for encryption")); 8822 8823 i_taskEncryptSettingsSetup(&CryptoSettingsRead, NULL, it->second.c_str(), task.mstrOldPassword.c_str(), 8824 false /* fCreateKeyStore */); 8825 vrc = VDFilterAdd(pDisk, "CRYPT", VD_FILTER_FLAGS_READ, CryptoSettingsRead.vdFilterIfaces); 8826 if (RT_FAILURE(vrc)) 8827 throw setError(VBOX_E_INVALID_OBJECT_STATE, 8828 tr("Failed to load the decryption filter: %s"), 8829 i_vdError(vrc).c_str()); 8830 } 8831 8832 if (task.mstrNewPassword.isNotEmpty()) 8833 { 8834 if (task.mstrCipher.isEmpty()) 8835 throw setError(VBOX_E_OBJECT_NOT_FOUND, 8836 tr("No valid cipher identifier was given for encryption")); 8837 8838 i_taskEncryptSettingsSetup(&CryptoSettingsWrite, task.mstrCipher.c_str(), NULL, 8839 task.mstrNewPassword.c_str(), true /* fCreateKeyStore */); 8840 vrc = VDFilterAdd(pDisk, "CRYPT", VD_FILTER_FLAGS_WRITE, CryptoSettingsWrite.vdFilterIfaces); 8841 if (RT_FAILURE(vrc)) 8842 throw setError(VBOX_E_INVALID_OBJECT_STATE, 8843 tr("Failed to load the encryption filter: %s"), 8844 i_vdError(vrc).c_str()); 8845 } 8846 8847 /* Open all media in the chain. */ 8848 MediumLockList::Base::const_iterator mediumListBegin = 8849 task.mpMediumLockList->GetBegin(); 8850 MediumLockList::Base::const_iterator mediumListEnd = 8851 task.mpMediumLockList->GetEnd(); 8852 MediumLockList::Base::const_iterator mediumListLast = 8853 mediumListEnd; 8854 mediumListLast--; 8855 for (MediumLockList::Base::const_iterator it = mediumListBegin; 8856 it != mediumListEnd; 8857 ++it) 8858 { 8859 const MediumLock &mediumLock = *it; 8860 const ComObjPtr<Medium> &pMedium = mediumLock.GetMedium(); 8861 AutoReadLock alock(pMedium COMMA_LOCKVAL_SRC_POS); 8862 8863 /* sanity check */ 8864 if (it == mediumListLast) 8865 Assert(pMedium->m->state == MediumState_LockedWrite); 8866 else 8867 Assert(pMedium->m->state == MediumState_LockedRead); 8868 8869 /* Open all media but last in read-only mode. Do not handle 8870 * shareable media, as compaction and sharing are mutually 8871 * exclusive. */ 8872 vrc = VDOpen(pDisk, 8873 pMedium->m->strFormat.c_str(), 8874 pMedium->m->strLocationFull.c_str(), 8875 m->uOpenFlagsDef | (it == mediumListLast ? VD_OPEN_FLAGS_NORMAL : VD_OPEN_FLAGS_READONLY), 8876 pMedium->m->vdImageIfaces); 8877 if (RT_FAILURE(vrc)) 8878 throw setError(VBOX_E_FILE_ERROR, 8879 tr("Could not open the medium storage unit '%s'%s"), 8880 pMedium->m->strLocationFull.c_str(), 8881 i_vdError(vrc).c_str()); 8882 } 8883 8884 Assert(m->state == MediumState_LockedWrite); 8885 8886 Utf8Str location(m->strLocationFull); 8887 8888 /* unlock before the potentially lengthy operation */ 8889 thisLock.release(); 8890 8891 /** @todo: Move the copying to the VD library and think about how to handle an I/O error 8892 * in the middle of the process. Implement progress interface. */ 8893 uint64_t uOffset = 0; 8894 size_t cbBuf = 2*_1M; 8895 uint64_t cbDisk = VDGetSize(pDisk, VD_LAST_IMAGE); 8896 8897 if (!cbDisk) 8898 throw setError(VBOX_E_FILE_ERROR, 8899 tr("Could not query the size of the disk '%s'"), 8900 m->strLocationFull.c_str()); 8901 8902 pvBuf = RTMemAllocZ(cbBuf); 8903 if (!pvBuf) 8904 throw setError(VBOX_E_INVALID_OBJECT_STATE, 8905 tr("Could not allocate %zu bytes of memory for the encryption"), 8906 cbBuf); 8907 8908 while (uOffset < cbDisk) 8909 { 8910 size_t cbCopy = RT_MIN(cbBuf, cbDisk - uOffset); 8911 vrc = VDRead(pDisk, uOffset, pvBuf, cbCopy); 8912 if (RT_FAILURE(vrc)) 8913 throw setError(VBOX_E_INVALID_OBJECT_STATE, 8914 tr("Could not read the original data from the image at offset %llu: %Rrc"), 8915 uOffset, vrc); 8916 8917 /* Write back, the filter will do the encryption if configured. */ 8918 vrc = VDWrite(pDisk, uOffset, pvBuf, cbCopy); 8919 if (RT_FAILURE(vrc)) 8920 throw setError(VBOX_E_INVALID_OBJECT_STATE, 8921 tr("Could not write the data to the image at offset %llu: %Rrc"), 8922 uOffset, vrc); 8923 8924 uOffset += cbCopy; 8925 } 8926 8927 thisLock.acquire(); 8928 /* If everything went well set the new key store. */ 8929 settings::StringsMap::iterator it = m->mapProperties.find("CRYPT/KeyStore"); 8930 if (it != m->mapProperties.end()) 8931 m->mapProperties.erase(it); 8932 8933 if (CryptoSettingsWrite.pszKeyStore) 8934 m->mapProperties["CRYPT/KeyStore"] = Utf8Str(CryptoSettingsWrite.pszKeyStore); 8935 8936 thisLock.release(); 8937 i_markRegistriesModified(); 8938 m->pVirtualBox->i_saveModifiedRegistries(); 8939 } 8940 catch (HRESULT aRC) { rc = aRC; } 8941 8942 if (pvBuf) 8943 RTMemFree(pvBuf); 8944 8945 VDDestroy(pDisk); 8946 # else 8947 throw setError(VBOX_E_NOT_SUPPORTED, 8948 tr("Encryption is not supported because extension pack support is not built in")); 8949 # endif 8950 8951 8952 } 8953 catch (HRESULT aRC) { rc = aRC; } 8954 8955 /* Everything is explicitly unlocked when the task exits, 8956 * as the task destruction also destroys the media chain. */ 8957 8958 return rc; 8959 } 8960 8406 8961 /* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note:
See TracChangeset
for help on using the changeset viewer.