/* Unregister this VSS hardware provider from the system */ STDAPI DllUnregisterServer(void) { TCHAR key[256]; COMInitializer initializer; COMPointer<IVssAdmin> pVssAdmin; HRESULT hr = CoCreateInstance(CLSID_VSSCoordinator, NULL, CLSCTX_ALL, IID_IVssAdmin, (void **)pVssAdmin.replace()); if (SUCCEEDED(hr)) { hr = pVssAdmin->UnregisterProvider(g_gProviderId); } else { errmsg(hr, "CoCreateInstance(VSSCoordinator) failed"); } sprintf(key, "CLSID\\%s", g_szClsid); SHDeleteKey(HKEY_CLASSES_ROOT, key); SHDeleteKey(HKEY_CLASSES_ROOT, g_szProgid); return S_OK; /* Uninstall should never fail */ }
STDAPI StopService(void) { HRESULT hr; COMInitializer initializer; COMPointer<IUnknown> pUnknown; COMPointer<ICOMAdminCatalog2> pCatalog; int count = 0; chk(QGAProviderFind(QGAProviderCount, (void *)&count)); if (count) { chk(CoCreateInstance(CLSID_COMAdminCatalog, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)pUnknown.replace())); chk(pUnknown->QueryInterface(IID_ICOMAdminCatalog2, (void **)pCatalog.replace())); chk(pCatalog->ShutdownApplication(_bstr_t(QGA_PROVIDER_LNAME))); } out: return hr; }
void requester_thaw(int *num_vols, void *mountpints, ErrorSet *errset) { COMPointer<IVssAsync> pAsync; if (!vss_ctx.hEventThaw) { /* * In this case, DoSnapshotSet is aborted or not started, * and no volumes must be frozen. We return without an error. */ *num_vols = 0; return; } /* Tell the provider that the snapshot is finished. */ SetEvent(vss_ctx.hEventThaw); assert(vss_ctx.pVssbc); assert(vss_ctx.pAsyncSnapshot); HRESULT hr = WaitForAsync(vss_ctx.pAsyncSnapshot); switch (hr) { case VSS_S_ASYNC_FINISHED: hr = vss_ctx.pVssbc->BackupComplete(pAsync.replace()); if (SUCCEEDED(hr)) { hr = WaitForAsync(pAsync); } if (FAILED(hr)) { err_set(errset, hr, "failed to complete backup"); } break; case (HRESULT)VSS_E_OBJECT_NOT_FOUND: /* * On Windows earlier than 2008 SP2 which does not support * VSS_VOLSNAP_ATTR_NO_AUTORECOVERY context, the final commit is not * skipped and VSS is aborted by VSS_E_OBJECT_NOT_FOUND. However, as * the system had been frozen until fsfreeze-thaw command was issued, * we ignore this error. */ vss_ctx.pVssbc->AbortBackup(); break; case VSS_E_UNEXPECTED_PROVIDER_ERROR: if (WaitForSingleObject(vss_ctx.hEventTimeout, 0) != WAIT_OBJECT_0) { err_set(errset, hr, "unexpected error in VSS provider"); break; } /* fall through if hEventTimeout is signaled */ case (HRESULT)VSS_E_HOLD_WRITES_TIMEOUT: err_set(errset, hr, "couldn't hold writes: " "fsfreeze is limited up to 10 seconds"); break; default: err_set(errset, hr, "failed to do snapshot set"); } if (err_is_set(errset)) { vss_ctx.pVssbc->AbortBackup(); } *num_vols = vss_ctx.cFrozenVols; requester_cleanup(); CoUninitialize(); StopService(); }
void requester_freeze(int *num_vols, void *mountpoints, ErrorSet *errset) { COMPointer<IVssAsync> pAsync; HANDLE volume; HRESULT hr; LONG ctx; GUID guidSnapshotSet = GUID_NULL; SECURITY_DESCRIPTOR sd; SECURITY_ATTRIBUTES sa; WCHAR short_volume_name[64], *display_name = short_volume_name; DWORD wait_status; int num_fixed_drives = 0, i; int num_mount_points = 0; if (vss_ctx.pVssbc) { /* already frozen */ *num_vols = 0; return; } CoInitialize(NULL); /* Allow unrestricted access to events */ InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = &sd; sa.bInheritHandle = FALSE; vss_ctx.hEventFrozen = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_FROZEN); if (!vss_ctx.hEventFrozen) { err_set(errset, GetLastError(), "failed to create event %s", EVENT_NAME_FROZEN); goto out; } vss_ctx.hEventThaw = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_THAW); if (!vss_ctx.hEventThaw) { err_set(errset, GetLastError(), "failed to create event %s", EVENT_NAME_THAW); goto out; } vss_ctx.hEventTimeout = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_TIMEOUT); if (!vss_ctx.hEventTimeout) { err_set(errset, GetLastError(), "failed to create event %s", EVENT_NAME_TIMEOUT); goto out; } assert(pCreateVssBackupComponents != NULL); hr = pCreateVssBackupComponents(&vss_ctx.pVssbc); if (FAILED(hr)) { err_set(errset, hr, "failed to create VSS backup components"); goto out; } hr = vss_ctx.pVssbc->InitializeForBackup(); if (FAILED(hr)) { err_set(errset, hr, "failed to initialize for backup"); goto out; } hr = vss_ctx.pVssbc->SetBackupState(true, true, VSS_BT_FULL, false); if (FAILED(hr)) { err_set(errset, hr, "failed to set backup state"); goto out; } /* * Currently writable snapshots are not supported. * To prevent the final commit (which requires to write to snapshots), * ATTR_NO_AUTORECOVERY and ATTR_TRANSPORTABLE are specified here. */ ctx = VSS_CTX_APP_ROLLBACK | VSS_VOLSNAP_ATTR_TRANSPORTABLE | VSS_VOLSNAP_ATTR_NO_AUTORECOVERY | VSS_VOLSNAP_ATTR_TXF_RECOVERY; hr = vss_ctx.pVssbc->SetContext(ctx); if (hr == (HRESULT)VSS_E_UNSUPPORTED_CONTEXT) { /* Non-server version of Windows doesn't support ATTR_TRANSPORTABLE */ ctx &= ~VSS_VOLSNAP_ATTR_TRANSPORTABLE; hr = vss_ctx.pVssbc->SetContext(ctx); } if (FAILED(hr)) { err_set(errset, hr, "failed to set backup context"); goto out; } hr = vss_ctx.pVssbc->GatherWriterMetadata(pAsync.replace()); if (SUCCEEDED(hr)) { hr = WaitForAsync(pAsync); } if (FAILED(hr)) { err_set(errset, hr, "failed to gather writer metadata"); goto out; } AddComponents(errset); if (err_is_set(errset)) { goto out; } hr = vss_ctx.pVssbc->StartSnapshotSet(&guidSnapshotSet); if (FAILED(hr)) { err_set(errset, hr, "failed to start snapshot set"); goto out; } if (mountpoints) { PWCHAR volume_name_wchar; for (volList *list = (volList *)mountpoints; list; list = list->next) { size_t len = strlen(list->value) + 1; size_t converted = 0; VSS_ID pid; volume_name_wchar = new wchar_t[len]; mbstowcs_s(&converted, volume_name_wchar, len, list->value, _TRUNCATE); hr = vss_ctx.pVssbc->AddToSnapshotSet(volume_name_wchar, g_gProviderId, &pid); if (FAILED(hr)) { err_set(errset, hr, "failed to add %S to snapshot set", volume_name_wchar); delete volume_name_wchar; goto out; } num_mount_points++; delete volume_name_wchar; } if (num_mount_points == 0) { /* If there is no valid mount points, just exit. */ goto out; } } if (!mountpoints) { volume = FindFirstVolumeW(short_volume_name, sizeof(short_volume_name)); if (volume == INVALID_HANDLE_VALUE) { err_set(errset, hr, "failed to find first volume"); goto out; } for (;;) { if (GetDriveTypeW(short_volume_name) == DRIVE_FIXED) { VSS_ID pid; hr = vss_ctx.pVssbc->AddToSnapshotSet(short_volume_name, g_gProviderId, &pid); if (FAILED(hr)) { WCHAR volume_path_name[PATH_MAX]; if (GetVolumePathNamesForVolumeNameW( short_volume_name, volume_path_name, sizeof(volume_path_name), NULL) && *volume_path_name) { display_name = volume_path_name; } err_set(errset, hr, "failed to add %S to snapshot set", display_name); FindVolumeClose(volume); goto out; } num_fixed_drives++; } if (!FindNextVolumeW(volume, short_volume_name, sizeof(short_volume_name))) { FindVolumeClose(volume); break; } } if (num_fixed_drives == 0) { goto out; /* If there is no fixed drive, just exit. */ } } hr = vss_ctx.pVssbc->PrepareForBackup(pAsync.replace()); if (SUCCEEDED(hr)) { hr = WaitForAsync(pAsync); } if (FAILED(hr)) { err_set(errset, hr, "failed to prepare for backup"); goto out; } hr = vss_ctx.pVssbc->GatherWriterStatus(pAsync.replace()); if (SUCCEEDED(hr)) { hr = WaitForAsync(pAsync); } if (FAILED(hr)) { err_set(errset, hr, "failed to gather writer status"); goto out; } /* * Start VSS quiescing operations. * CQGAVssProvider::CommitSnapshots will kick vss_ctx.hEventFrozen * after the applications and filesystems are frozen. */ hr = vss_ctx.pVssbc->DoSnapshotSet(&vss_ctx.pAsyncSnapshot); if (FAILED(hr)) { err_set(errset, hr, "failed to do snapshot set"); goto out; } /* Need to call QueryStatus several times to make VSS provider progress */ for (i = 0; i < VSS_TIMEOUT_FREEZE_MSEC/VSS_TIMEOUT_EVENT_MSEC; i++) { HRESULT hr2 = vss_ctx.pAsyncSnapshot->QueryStatus(&hr, NULL); if (FAILED(hr2)) { err_set(errset, hr, "failed to do snapshot set"); goto out; } if (hr != VSS_S_ASYNC_PENDING) { err_set(errset, E_FAIL, "DoSnapshotSet exited without Frozen event"); goto out; } wait_status = WaitForSingleObject(vss_ctx.hEventFrozen, VSS_TIMEOUT_EVENT_MSEC); if (wait_status != WAIT_TIMEOUT) { break; } } if (wait_status == WAIT_TIMEOUT) { err_set(errset, E_FAIL, "timeout when try to receive Frozen event from VSS provider"); /* If we are here, VSS had timeout. * Don't call AbortBackup, just return directly. */ goto out1; } if (wait_status != WAIT_OBJECT_0) { err_set(errset, E_FAIL, "couldn't receive Frozen event from VSS provider"); goto out; } if (mountpoints) { *num_vols = vss_ctx.cFrozenVols = num_mount_points; } else { *num_vols = vss_ctx.cFrozenVols = num_fixed_drives; } return; out: if (vss_ctx.pVssbc) { vss_ctx.pVssbc->AbortBackup(); } out1: requester_cleanup(); CoUninitialize(); }
static void AddComponents(ErrorSet *errset) { unsigned int cWriters, i; VSS_ID id, idInstance, idWriter; BSTR bstrWriterName = NULL; VSS_USAGE_TYPE usage; VSS_SOURCE_TYPE source; unsigned int cComponents, c1, c2, j; COMPointer<IVssExamineWriterMetadata> pMetadata; COMPointer<IVssWMComponent> pComponent; PVSSCOMPONENTINFO info; HRESULT hr; hr = vss_ctx.pVssbc->GetWriterMetadataCount(&cWriters); if (FAILED(hr)) { err_set(errset, hr, "failed to get writer metadata count"); goto out; } for (i = 0; i < cWriters; i++) { hr = vss_ctx.pVssbc->GetWriterMetadata(i, &id, pMetadata.replace()); if (FAILED(hr)) { err_set(errset, hr, "failed to get writer metadata of %d/%d", i, cWriters); goto out; } hr = pMetadata->GetIdentity(&idInstance, &idWriter, &bstrWriterName, &usage, &source); if (FAILED(hr)) { err_set(errset, hr, "failed to get identity of writer %d/%d", i, cWriters); goto out; } hr = pMetadata->GetFileCounts(&c1, &c2, &cComponents); if (FAILED(hr)) { err_set(errset, hr, "failed to get file counts of %S", bstrWriterName); goto out; } for (j = 0; j < cComponents; j++) { hr = pMetadata->GetComponent(j, pComponent.replace()); if (FAILED(hr)) { err_set(errset, hr, "failed to get component %d/%d of %S", j, cComponents, bstrWriterName); goto out; } hr = pComponent->GetComponentInfo(&info); if (FAILED(hr)) { err_set(errset, hr, "failed to get component info %d/%d of %S", j, cComponents, bstrWriterName); goto out; } if (info->bSelectable) { hr = vss_ctx.pVssbc->AddComponent(idInstance, idWriter, info->type, info->bstrLogicalPath, info->bstrComponentName); if (FAILED(hr)) { err_set(errset, hr, "failed to add component %S(%S)", info->bstrComponentName, bstrWriterName); goto out; } } SysFreeString(bstrWriterName); bstrWriterName = NULL; pComponent->FreeComponentInfo(info); info = NULL; } } out: if (bstrWriterName) { SysFreeString(bstrWriterName); } if (pComponent && info) { pComponent->FreeComponentInfo(info); } }
/* Lookup Administrators group name from winmgmt */ static HRESULT GetAdminName(_bstr_t *name) { HRESULT hr; COMPointer<IWbemLocator> pLoc; COMPointer<IWbemServices> pSvc; COMPointer<IEnumWbemClassObject> pEnum; COMPointer<IWbemClassObject> pWobj; ULONG returned; _variant_t var; chk(CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *)pLoc.replace())); chk(pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), NULL, NULL, NULL, 0, 0, 0, pSvc.replace())); chk(CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE)); chk(pSvc->ExecQuery(_bstr_t(L"WQL"), _bstr_t(L"select * from Win32_Account where " "SID='S-1-5-32-544' and localAccount=TRUE"), WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, pEnum.replace())); if (!pEnum) { hr = E_FAIL; errmsg(hr, "Failed to query for Administrators"); goto out; } chk(pEnum->Next(WBEM_INFINITE, 1, pWobj.replace(), &returned)); if (returned == 0) { hr = E_FAIL; errmsg(hr, "No Administrators found"); goto out; } chk(pWobj->Get(_bstr_t(L"Name"), 0, &var, 0, 0)); try { *name = var; } catch(...) { hr = E_FAIL; errmsg(hr, "Failed to get name of Administrators"); goto out; } out: return hr; }
/* Register this dll as a VSS provider */ STDAPI DllRegisterServer(void) { COMInitializer initializer; COMPointer<IVssAdmin> pVssAdmin; HRESULT hr = E_FAIL; char dllPath[MAX_PATH]; char key[256]; if (!g_hinstDll) { errmsg_dialog(hr, "Module instance is not available"); goto out; } /* Add this module to registery */ sprintf(key, "CLSID\\%s", g_szClsid); if (!CreateRegistryKey(key, NULL, g_szClsid)) { goto out; } if (!GetModuleFileName(g_hinstDll, dllPath, sizeof(dllPath))) { errmsg_dialog(GetLastError(), "GetModuleFileName failed"); goto out; } sprintf(key, "CLSID\\%s\\InprocServer32", g_szClsid); if (!CreateRegistryKey(key, NULL, dllPath)) { goto out; } if (!CreateRegistryKey(key, "ThreadingModel", "Apartment")) { goto out; } sprintf(key, "CLSID\\%s\\ProgID", g_szClsid); if (!CreateRegistryKey(key, NULL, g_szProgid)) { goto out; } if (!CreateRegistryKey(g_szProgid, NULL, QGA_PROVIDER_NAME)) { goto out; } sprintf(key, "%s\\CLSID", g_szProgid); if (!CreateRegistryKey(key, NULL, g_szClsid)) { goto out; } hr = CoCreateInstance(CLSID_VSSCoordinator, NULL, CLSCTX_ALL, IID_IVssAdmin, (void **)pVssAdmin.replace()); if (FAILED(hr)) { errmsg_dialog(hr, "CoCreateInstance(VSSCoordinator) failed"); goto out; } hr = pVssAdmin->RegisterProvider(g_gProviderId, CLSID_QGAVSSProvider, const_cast<WCHAR*>(QGA_PROVIDER_LNAME), VSS_PROV_SOFTWARE, const_cast<WCHAR*>(QGA_PROVIDER_VERSION), g_gProviderVersion); if (FAILED(hr)) { errmsg_dialog(hr, "RegisterProvider failed"); } out: if (FAILED(hr)) { DllUnregisterServer(); } return hr; }
/* Register this module to COM+ Applications Catalog */ STDAPI COMRegister(void) { HRESULT hr; COMInitializer initializer; COMPointer<IUnknown> pUnknown; COMPointer<ICOMAdminCatalog2> pCatalog; COMPointer<ICatalogCollection> pApps, pRoles, pUsersInRole; COMPointer<ICatalogObject> pObj; long n; _bstr_t name; _variant_t key; CHAR dllPath[MAX_PATH], tlbPath[MAX_PATH]; bool unregisterOnFailure = false; int count = 0; DWORD bufferLen = BUFFER_SIZE; wchar_t buffer[BUFFER_SIZE]; const wchar_t *administratorsGroupSID = L"S-1-5-32-544"; const wchar_t *systemUserSID = L"S-1-5-18"; if (!g_hinstDll) { errmsg(E_FAIL, "Failed to initialize DLL"); return E_FAIL; } chk(QGAProviderFind(QGAProviderCount, (void *)&count)); if (count) { errmsg(E_ABORT, "QGA VSS Provider is already installed"); return E_ABORT; } chk(CoCreateInstance(CLSID_COMAdminCatalog, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)pUnknown.replace())); chk(pUnknown->QueryInterface(IID_ICOMAdminCatalog2, (void **)pCatalog.replace())); /* Install COM+ Component */ chk(pCatalog->GetCollection(_bstr_t(L"Applications"), (IDispatch **)pApps.replace())); chk(pApps->Populate()); chk(pApps->Add((IDispatch **)&pObj)); chk(put_Value(pObj, L"Name", QGA_PROVIDER_LNAME)); chk(put_Value(pObj, L"Description", QGA_PROVIDER_LNAME)); chk(put_Value(pObj, L"ApplicationAccessChecksEnabled", true)); chk(put_Value(pObj, L"Authentication", short(6))); chk(put_Value(pObj, L"AuthenticationCapability", short(2))); chk(put_Value(pObj, L"ImpersonationLevel", short(2))); chk(pApps->SaveChanges(&n)); /* The app should be deleted if something fails after SaveChanges */ unregisterOnFailure = true; chk(pObj->get_Key(&key)); if (!GetModuleFileName(g_hinstDll, dllPath, sizeof(dllPath))) { hr = HRESULT_FROM_WIN32(GetLastError()); errmsg(hr, "GetModuleFileName failed"); goto out; } n = strlen(dllPath); if (n < 3) { hr = E_FAIL; errmsg(hr, "Failed to lookup dll"); goto out; } strcpy(tlbPath, dllPath); strcpy(tlbPath+n-3, "tlb"); fprintf(stderr, "Registering " QGA_PROVIDER_NAME ":\n"); fprintf(stderr, " %s\n", dllPath); fprintf(stderr, " %s\n", tlbPath); if (!PathFileExists(tlbPath)) { hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); errmsg(hr, "Failed to lookup tlb"); goto out; } chk(pCatalog->CreateServiceForApplication( _bstr_t(QGA_PROVIDER_LNAME), _bstr_t(QGA_PROVIDER_LNAME), _bstr_t(L"SERVICE_DEMAND_START"), _bstr_t(L"SERVICE_ERROR_NORMAL"), _bstr_t(L""), _bstr_t(L".\\localsystem"), _bstr_t(L""), FALSE)); chk(pCatalog->InstallComponent(_bstr_t(QGA_PROVIDER_LNAME), _bstr_t(dllPath), _bstr_t(tlbPath), _bstr_t(""))); /* Setup roles of the applicaion */ chk(getNameByStringSID(administratorsGroupSID, buffer, &bufferLen)); chk(pApps->GetCollection(_bstr_t(L"Roles"), key, (IDispatch **)pRoles.replace())); chk(pRoles->Populate()); chk(pRoles->Add((IDispatch **)pObj.replace())); chk(put_Value(pObj, L"Name", buffer)); chk(put_Value(pObj, L"Description", L"Administrators group")); chk(pRoles->SaveChanges(&n)); chk(pObj->get_Key(&key)); /* Setup users in the role */ chk(pRoles->GetCollection(_bstr_t(L"UsersInRole"), key, (IDispatch **)pUsersInRole.replace())); chk(pUsersInRole->Populate()); chk(pUsersInRole->Add((IDispatch **)pObj.replace())); chk(GetAdminName(&name)); chk(put_Value(pObj, L"User", _bstr_t(".\\") + name)); bufferLen = BUFFER_SIZE; chk(getNameByStringSID(systemUserSID, buffer, &bufferLen)); chk(pUsersInRole->Add((IDispatch **)pObj.replace())); chk(put_Value(pObj, L"User", buffer)); chk(pUsersInRole->SaveChanges(&n)); out: if (unregisterOnFailure && FAILED(hr)) { COMUnregister(); } return hr; }
/* Find and iterate QGA VSS provider in COM+ Application Catalog */ static HRESULT QGAProviderFind( HRESULT (*found)(ICatalogCollection *, int, void *), void *arg) { HRESULT hr; COMInitializer initializer; COMPointer<IUnknown> pUnknown; COMPointer<ICOMAdminCatalog2> pCatalog; COMPointer<ICatalogCollection> pColl; COMPointer<ICatalogObject> pObj; _variant_t var; long i, n; chk(CoCreateInstance(CLSID_COMAdminCatalog, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)pUnknown.replace())); chk(pUnknown->QueryInterface(IID_ICOMAdminCatalog2, (void **)pCatalog.replace())); chk(pCatalog->GetCollection(_bstr_t(L"Applications"), (IDispatch **)pColl.replace())); chk(pColl->Populate()); chk(pColl->get_Count(&n)); for (i = n - 1; i >= 0; i--) { chk(pColl->get_Item(i, (IDispatch **)pObj.replace())); chk(pObj->get_Value(_bstr_t(L"Name"), &var)); if (var == _variant_t(QGA_PROVIDER_LNAME)) { if (FAILED(found(pColl, i, arg))) { goto out; } } } chk(pColl->SaveChanges(&n)); out: return hr; }