1*b39297aeSTomoki Sekiyama /* 2*b39297aeSTomoki Sekiyama * QEMU Guest Agent win32 VSS Provider installer 3*b39297aeSTomoki Sekiyama * 4*b39297aeSTomoki Sekiyama * Copyright Hitachi Data Systems Corp. 2013 5*b39297aeSTomoki Sekiyama * 6*b39297aeSTomoki Sekiyama * Authors: 7*b39297aeSTomoki Sekiyama * Tomoki Sekiyama <tomoki.sekiyama@hds.com> 8*b39297aeSTomoki Sekiyama * 9*b39297aeSTomoki Sekiyama * This work is licensed under the terms of the GNU GPL, version 2 or later. 10*b39297aeSTomoki Sekiyama * See the COPYING file in the top-level directory. 11*b39297aeSTomoki Sekiyama */ 12*b39297aeSTomoki Sekiyama 13*b39297aeSTomoki Sekiyama #include <stdio.h> 14*b39297aeSTomoki Sekiyama #include <string.h> 15*b39297aeSTomoki Sekiyama 16*b39297aeSTomoki Sekiyama #include "vss-common.h" 17*b39297aeSTomoki Sekiyama #include "inc/win2003/vscoordint.h" 18*b39297aeSTomoki Sekiyama 19*b39297aeSTomoki Sekiyama #include <comadmin.h> 20*b39297aeSTomoki Sekiyama #include <wbemidl.h> 21*b39297aeSTomoki Sekiyama #include <comdef.h> 22*b39297aeSTomoki Sekiyama #include <comutil.h> 23*b39297aeSTomoki Sekiyama 24*b39297aeSTomoki Sekiyama extern HINSTANCE g_hinstDll; 25*b39297aeSTomoki Sekiyama 26*b39297aeSTomoki Sekiyama const GUID CLSID_COMAdminCatalog = { 0xF618C514, 0xDFB8, 0x11d1, 27*b39297aeSTomoki Sekiyama {0xA2, 0xCF, 0x00, 0x80, 0x5F, 0xC7, 0x92, 0x35} }; 28*b39297aeSTomoki Sekiyama const GUID IID_ICOMAdminCatalog = { 0xDD662187, 0xDFC2, 0x11d1, 29*b39297aeSTomoki Sekiyama {0xA2, 0xCF, 0x00, 0x80, 0x5F, 0xC7, 0x92, 0x35} }; 30*b39297aeSTomoki Sekiyama const GUID CLSID_WbemLocator = { 0x4590f811, 0x1d3a, 0x11d0, 31*b39297aeSTomoki Sekiyama {0x89, 0x1f, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24} }; 32*b39297aeSTomoki Sekiyama const GUID IID_IWbemLocator = { 0xdc12a687, 0x737f, 0x11cf, 33*b39297aeSTomoki Sekiyama {0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24} }; 34*b39297aeSTomoki Sekiyama 35*b39297aeSTomoki Sekiyama void errmsg(DWORD err, const char *text) 36*b39297aeSTomoki Sekiyama { 37*b39297aeSTomoki Sekiyama /* 38*b39297aeSTomoki Sekiyama * `text' contains function call statement when errmsg is called via chk(). 39*b39297aeSTomoki Sekiyama * To make error message more readable, we cut off the text after '('. 40*b39297aeSTomoki Sekiyama * If text doesn't contains '(', negative precision is given, which is 41*b39297aeSTomoki Sekiyama * treated as though it were missing. 42*b39297aeSTomoki Sekiyama */ 43*b39297aeSTomoki Sekiyama char *msg = NULL, *nul = strchr(text, '('); 44*b39297aeSTomoki Sekiyama int len = nul ? nul - text : -1; 45*b39297aeSTomoki Sekiyama 46*b39297aeSTomoki Sekiyama FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 47*b39297aeSTomoki Sekiyama FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 48*b39297aeSTomoki Sekiyama NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 49*b39297aeSTomoki Sekiyama (char *)&msg, 0, NULL); 50*b39297aeSTomoki Sekiyama fprintf(stderr, "%.*s. (Error: %lx) %s\n", len, text, err, msg); 51*b39297aeSTomoki Sekiyama LocalFree(msg); 52*b39297aeSTomoki Sekiyama } 53*b39297aeSTomoki Sekiyama 54*b39297aeSTomoki Sekiyama static void errmsg_dialog(DWORD err, const char *text, const char *opt = "") 55*b39297aeSTomoki Sekiyama { 56*b39297aeSTomoki Sekiyama char *msg, buf[512]; 57*b39297aeSTomoki Sekiyama 58*b39297aeSTomoki Sekiyama FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 59*b39297aeSTomoki Sekiyama FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 60*b39297aeSTomoki Sekiyama NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 61*b39297aeSTomoki Sekiyama (char *)&msg, 0, NULL); 62*b39297aeSTomoki Sekiyama snprintf(buf, sizeof(buf), "%s%s. (Error: %lx) %s", text, opt, err, msg); 63*b39297aeSTomoki Sekiyama MessageBox(NULL, buf, "Error from " QGA_PROVIDER_NAME, MB_OK|MB_ICONERROR); 64*b39297aeSTomoki Sekiyama LocalFree(msg); 65*b39297aeSTomoki Sekiyama } 66*b39297aeSTomoki Sekiyama 67*b39297aeSTomoki Sekiyama #define _chk(hr, status, msg, err_label) \ 68*b39297aeSTomoki Sekiyama do { \ 69*b39297aeSTomoki Sekiyama hr = (status); \ 70*b39297aeSTomoki Sekiyama if (FAILED(hr)) { \ 71*b39297aeSTomoki Sekiyama errmsg(hr, msg); \ 72*b39297aeSTomoki Sekiyama goto err_label; \ 73*b39297aeSTomoki Sekiyama } \ 74*b39297aeSTomoki Sekiyama } while (0) 75*b39297aeSTomoki Sekiyama 76*b39297aeSTomoki Sekiyama #define chk(status) _chk(hr, status, "Failed to " #status, out) 77*b39297aeSTomoki Sekiyama 78*b39297aeSTomoki Sekiyama void __stdcall _com_issue_error(HRESULT hr) 79*b39297aeSTomoki Sekiyama { 80*b39297aeSTomoki Sekiyama errmsg(hr, "Unexpected error in COM"); 81*b39297aeSTomoki Sekiyama } 82*b39297aeSTomoki Sekiyama 83*b39297aeSTomoki Sekiyama template<class T> 84*b39297aeSTomoki Sekiyama HRESULT put_Value(ICatalogObject *pObj, LPCWSTR name, T val) 85*b39297aeSTomoki Sekiyama { 86*b39297aeSTomoki Sekiyama return pObj->put_Value(_bstr_t(name), _variant_t(val)); 87*b39297aeSTomoki Sekiyama } 88*b39297aeSTomoki Sekiyama 89*b39297aeSTomoki Sekiyama /* Lookup Administrators group name from winmgmt */ 90*b39297aeSTomoki Sekiyama static HRESULT GetAdminName(_bstr_t *name) 91*b39297aeSTomoki Sekiyama { 92*b39297aeSTomoki Sekiyama HRESULT hr; 93*b39297aeSTomoki Sekiyama COMPointer<IWbemLocator> pLoc; 94*b39297aeSTomoki Sekiyama COMPointer<IWbemServices> pSvc; 95*b39297aeSTomoki Sekiyama COMPointer<IEnumWbemClassObject> pEnum; 96*b39297aeSTomoki Sekiyama COMPointer<IWbemClassObject> pWobj; 97*b39297aeSTomoki Sekiyama ULONG returned; 98*b39297aeSTomoki Sekiyama _variant_t var; 99*b39297aeSTomoki Sekiyama 100*b39297aeSTomoki Sekiyama chk(CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, 101*b39297aeSTomoki Sekiyama IID_IWbemLocator, (LPVOID *)pLoc.replace())); 102*b39297aeSTomoki Sekiyama chk(pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), NULL, NULL, NULL, 103*b39297aeSTomoki Sekiyama 0, 0, 0, pSvc.replace())); 104*b39297aeSTomoki Sekiyama chk(CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, 105*b39297aeSTomoki Sekiyama NULL, RPC_C_AUTHN_LEVEL_CALL, 106*b39297aeSTomoki Sekiyama RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE)); 107*b39297aeSTomoki Sekiyama chk(pSvc->ExecQuery(_bstr_t(L"WQL"), 108*b39297aeSTomoki Sekiyama _bstr_t(L"select * from Win32_Account where " 109*b39297aeSTomoki Sekiyama "SID='S-1-5-32-544' and localAccount=TRUE"), 110*b39297aeSTomoki Sekiyama WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, 111*b39297aeSTomoki Sekiyama NULL, pEnum.replace())); 112*b39297aeSTomoki Sekiyama if (!pEnum) { 113*b39297aeSTomoki Sekiyama hr = E_FAIL; 114*b39297aeSTomoki Sekiyama errmsg(hr, "Failed to query for Administrators"); 115*b39297aeSTomoki Sekiyama goto out; 116*b39297aeSTomoki Sekiyama } 117*b39297aeSTomoki Sekiyama chk(pEnum->Next(WBEM_INFINITE, 1, pWobj.replace(), &returned)); 118*b39297aeSTomoki Sekiyama if (returned == 0) { 119*b39297aeSTomoki Sekiyama hr = E_FAIL; 120*b39297aeSTomoki Sekiyama errmsg(hr, "No Administrators found"); 121*b39297aeSTomoki Sekiyama goto out; 122*b39297aeSTomoki Sekiyama } 123*b39297aeSTomoki Sekiyama 124*b39297aeSTomoki Sekiyama chk(pWobj->Get(_bstr_t(L"Name"), 0, &var, 0, 0)); 125*b39297aeSTomoki Sekiyama try { 126*b39297aeSTomoki Sekiyama *name = var; 127*b39297aeSTomoki Sekiyama } catch(...) { 128*b39297aeSTomoki Sekiyama hr = E_FAIL; 129*b39297aeSTomoki Sekiyama errmsg(hr, "Failed to get name of Administrators"); 130*b39297aeSTomoki Sekiyama goto out; 131*b39297aeSTomoki Sekiyama } 132*b39297aeSTomoki Sekiyama 133*b39297aeSTomoki Sekiyama out: 134*b39297aeSTomoki Sekiyama return hr; 135*b39297aeSTomoki Sekiyama } 136*b39297aeSTomoki Sekiyama 137*b39297aeSTomoki Sekiyama /* Find and iterate QGA VSS provider in COM+ Application Catalog */ 138*b39297aeSTomoki Sekiyama static HRESULT QGAProviderFind( 139*b39297aeSTomoki Sekiyama HRESULT (*found)(ICatalogCollection *, int, void *), void *arg) 140*b39297aeSTomoki Sekiyama { 141*b39297aeSTomoki Sekiyama HRESULT hr; 142*b39297aeSTomoki Sekiyama COMInitializer initializer; 143*b39297aeSTomoki Sekiyama COMPointer<IUnknown> pUnknown; 144*b39297aeSTomoki Sekiyama COMPointer<ICOMAdminCatalog> pCatalog; 145*b39297aeSTomoki Sekiyama COMPointer<ICatalogCollection> pColl; 146*b39297aeSTomoki Sekiyama COMPointer<ICatalogObject> pObj; 147*b39297aeSTomoki Sekiyama _variant_t var; 148*b39297aeSTomoki Sekiyama long i, n; 149*b39297aeSTomoki Sekiyama 150*b39297aeSTomoki Sekiyama chk(CoCreateInstance(CLSID_COMAdminCatalog, NULL, CLSCTX_INPROC_SERVER, 151*b39297aeSTomoki Sekiyama IID_IUnknown, (void **)pUnknown.replace())); 152*b39297aeSTomoki Sekiyama chk(pUnknown->QueryInterface(IID_ICOMAdminCatalog, 153*b39297aeSTomoki Sekiyama (void **)pCatalog.replace())); 154*b39297aeSTomoki Sekiyama chk(pCatalog->GetCollection(_bstr_t(L"Applications"), 155*b39297aeSTomoki Sekiyama (IDispatch **)pColl.replace())); 156*b39297aeSTomoki Sekiyama chk(pColl->Populate()); 157*b39297aeSTomoki Sekiyama 158*b39297aeSTomoki Sekiyama chk(pColl->get_Count(&n)); 159*b39297aeSTomoki Sekiyama for (i = n - 1; i >= 0; i--) { 160*b39297aeSTomoki Sekiyama chk(pColl->get_Item(i, (IDispatch **)pObj.replace())); 161*b39297aeSTomoki Sekiyama chk(pObj->get_Value(_bstr_t(L"Name"), &var)); 162*b39297aeSTomoki Sekiyama if (var == _variant_t(QGA_PROVIDER_LNAME)) { 163*b39297aeSTomoki Sekiyama if (FAILED(found(pColl, i, arg))) { 164*b39297aeSTomoki Sekiyama goto out; 165*b39297aeSTomoki Sekiyama } 166*b39297aeSTomoki Sekiyama } 167*b39297aeSTomoki Sekiyama } 168*b39297aeSTomoki Sekiyama chk(pColl->SaveChanges(&n)); 169*b39297aeSTomoki Sekiyama 170*b39297aeSTomoki Sekiyama out: 171*b39297aeSTomoki Sekiyama return hr; 172*b39297aeSTomoki Sekiyama } 173*b39297aeSTomoki Sekiyama 174*b39297aeSTomoki Sekiyama /* Count QGA VSS provider in COM+ Application Catalog */ 175*b39297aeSTomoki Sekiyama static HRESULT QGAProviderCount(ICatalogCollection *coll, int i, void *arg) 176*b39297aeSTomoki Sekiyama { 177*b39297aeSTomoki Sekiyama (*(int *)arg)++; 178*b39297aeSTomoki Sekiyama return S_OK; 179*b39297aeSTomoki Sekiyama } 180*b39297aeSTomoki Sekiyama 181*b39297aeSTomoki Sekiyama /* Remove QGA VSS provider from COM+ Application Catalog Collection */ 182*b39297aeSTomoki Sekiyama static HRESULT QGAProviderRemove(ICatalogCollection *coll, int i, void *arg) 183*b39297aeSTomoki Sekiyama { 184*b39297aeSTomoki Sekiyama HRESULT hr; 185*b39297aeSTomoki Sekiyama 186*b39297aeSTomoki Sekiyama fprintf(stderr, "Removing COM+ Application: %s\n", QGA_PROVIDER_NAME); 187*b39297aeSTomoki Sekiyama chk(coll->Remove(i)); 188*b39297aeSTomoki Sekiyama out: 189*b39297aeSTomoki Sekiyama return hr; 190*b39297aeSTomoki Sekiyama } 191*b39297aeSTomoki Sekiyama 192*b39297aeSTomoki Sekiyama /* Unregister this module from COM+ Applications Catalog */ 193*b39297aeSTomoki Sekiyama STDAPI COMUnregister(void) 194*b39297aeSTomoki Sekiyama { 195*b39297aeSTomoki Sekiyama HRESULT hr; 196*b39297aeSTomoki Sekiyama 197*b39297aeSTomoki Sekiyama DllUnregisterServer(); 198*b39297aeSTomoki Sekiyama chk(QGAProviderFind(QGAProviderRemove, NULL)); 199*b39297aeSTomoki Sekiyama out: 200*b39297aeSTomoki Sekiyama return hr; 201*b39297aeSTomoki Sekiyama } 202*b39297aeSTomoki Sekiyama 203*b39297aeSTomoki Sekiyama /* Register this module to COM+ Applications Catalog */ 204*b39297aeSTomoki Sekiyama STDAPI COMRegister(void) 205*b39297aeSTomoki Sekiyama { 206*b39297aeSTomoki Sekiyama HRESULT hr; 207*b39297aeSTomoki Sekiyama COMInitializer initializer; 208*b39297aeSTomoki Sekiyama COMPointer<IUnknown> pUnknown; 209*b39297aeSTomoki Sekiyama COMPointer<ICOMAdminCatalog> pCatalog; 210*b39297aeSTomoki Sekiyama COMPointer<ICatalogCollection> pApps, pRoles, pUsersInRole; 211*b39297aeSTomoki Sekiyama COMPointer<ICatalogObject> pObj; 212*b39297aeSTomoki Sekiyama long n; 213*b39297aeSTomoki Sekiyama _bstr_t name; 214*b39297aeSTomoki Sekiyama _variant_t key; 215*b39297aeSTomoki Sekiyama CHAR dllPath[MAX_PATH], tlbPath[MAX_PATH]; 216*b39297aeSTomoki Sekiyama bool unregisterOnFailure = false; 217*b39297aeSTomoki Sekiyama int count = 0; 218*b39297aeSTomoki Sekiyama 219*b39297aeSTomoki Sekiyama if (!g_hinstDll) { 220*b39297aeSTomoki Sekiyama errmsg(E_FAIL, "Failed to initialize DLL"); 221*b39297aeSTomoki Sekiyama return E_FAIL; 222*b39297aeSTomoki Sekiyama } 223*b39297aeSTomoki Sekiyama 224*b39297aeSTomoki Sekiyama chk(QGAProviderFind(QGAProviderCount, (void *)&count)); 225*b39297aeSTomoki Sekiyama if (count) { 226*b39297aeSTomoki Sekiyama errmsg(E_ABORT, "QGA VSS Provider is already installed"); 227*b39297aeSTomoki Sekiyama return E_ABORT; 228*b39297aeSTomoki Sekiyama } 229*b39297aeSTomoki Sekiyama 230*b39297aeSTomoki Sekiyama chk(CoCreateInstance(CLSID_COMAdminCatalog, NULL, CLSCTX_INPROC_SERVER, 231*b39297aeSTomoki Sekiyama IID_IUnknown, (void **)pUnknown.replace())); 232*b39297aeSTomoki Sekiyama chk(pUnknown->QueryInterface(IID_ICOMAdminCatalog, 233*b39297aeSTomoki Sekiyama (void **)pCatalog.replace())); 234*b39297aeSTomoki Sekiyama 235*b39297aeSTomoki Sekiyama /* Install COM+ Component */ 236*b39297aeSTomoki Sekiyama 237*b39297aeSTomoki Sekiyama chk(pCatalog->GetCollection(_bstr_t(L"Applications"), 238*b39297aeSTomoki Sekiyama (IDispatch **)pApps.replace())); 239*b39297aeSTomoki Sekiyama chk(pApps->Populate()); 240*b39297aeSTomoki Sekiyama chk(pApps->Add((IDispatch **)&pObj)); 241*b39297aeSTomoki Sekiyama chk(put_Value(pObj, L"Name", QGA_PROVIDER_LNAME)); 242*b39297aeSTomoki Sekiyama chk(put_Value(pObj, L"Description", QGA_PROVIDER_LNAME)); 243*b39297aeSTomoki Sekiyama chk(put_Value(pObj, L"ApplicationAccessChecksEnabled", true)); 244*b39297aeSTomoki Sekiyama chk(put_Value(pObj, L"Authentication", short(6))); 245*b39297aeSTomoki Sekiyama chk(put_Value(pObj, L"AuthenticationCapability", short(2))); 246*b39297aeSTomoki Sekiyama chk(put_Value(pObj, L"ImpersonationLevel", short(2))); 247*b39297aeSTomoki Sekiyama chk(pApps->SaveChanges(&n)); 248*b39297aeSTomoki Sekiyama 249*b39297aeSTomoki Sekiyama /* The app should be deleted if something fails after SaveChanges */ 250*b39297aeSTomoki Sekiyama unregisterOnFailure = true; 251*b39297aeSTomoki Sekiyama 252*b39297aeSTomoki Sekiyama chk(pObj->get_Key(&key)); 253*b39297aeSTomoki Sekiyama 254*b39297aeSTomoki Sekiyama if (!GetModuleFileName(g_hinstDll, dllPath, sizeof(dllPath))) { 255*b39297aeSTomoki Sekiyama hr = HRESULT_FROM_WIN32(GetLastError()); 256*b39297aeSTomoki Sekiyama errmsg(hr, "GetModuleFileName failed"); 257*b39297aeSTomoki Sekiyama goto out; 258*b39297aeSTomoki Sekiyama } 259*b39297aeSTomoki Sekiyama n = strlen(dllPath); 260*b39297aeSTomoki Sekiyama if (n < 3) { 261*b39297aeSTomoki Sekiyama hr = E_FAIL; 262*b39297aeSTomoki Sekiyama errmsg(hr, "Failed to lookup dll"); 263*b39297aeSTomoki Sekiyama goto out; 264*b39297aeSTomoki Sekiyama } 265*b39297aeSTomoki Sekiyama strcpy(tlbPath, dllPath); 266*b39297aeSTomoki Sekiyama strcpy(tlbPath+n-3, "tlb"); 267*b39297aeSTomoki Sekiyama fprintf(stderr, "Registering " QGA_PROVIDER_NAME ":\n"); 268*b39297aeSTomoki Sekiyama fprintf(stderr, " %s\n", dllPath); 269*b39297aeSTomoki Sekiyama fprintf(stderr, " %s\n", tlbPath); 270*b39297aeSTomoki Sekiyama if (!PathFileExists(tlbPath)) { 271*b39297aeSTomoki Sekiyama hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); 272*b39297aeSTomoki Sekiyama errmsg(hr, "Failed to lookup tlb"); 273*b39297aeSTomoki Sekiyama goto out; 274*b39297aeSTomoki Sekiyama } 275*b39297aeSTomoki Sekiyama 276*b39297aeSTomoki Sekiyama chk(pCatalog->InstallComponent(_bstr_t(QGA_PROVIDER_LNAME), 277*b39297aeSTomoki Sekiyama _bstr_t(dllPath), _bstr_t(tlbPath), 278*b39297aeSTomoki Sekiyama _bstr_t(""))); 279*b39297aeSTomoki Sekiyama 280*b39297aeSTomoki Sekiyama /* Setup roles of the applicaion */ 281*b39297aeSTomoki Sekiyama 282*b39297aeSTomoki Sekiyama chk(pApps->GetCollection(_bstr_t(L"Roles"), key, 283*b39297aeSTomoki Sekiyama (IDispatch **)pRoles.replace())); 284*b39297aeSTomoki Sekiyama chk(pRoles->Populate()); 285*b39297aeSTomoki Sekiyama chk(pRoles->Add((IDispatch **)pObj.replace())); 286*b39297aeSTomoki Sekiyama chk(put_Value(pObj, L"Name", L"Administrators")); 287*b39297aeSTomoki Sekiyama chk(put_Value(pObj, L"Description", L"Administrators group")); 288*b39297aeSTomoki Sekiyama chk(pRoles->SaveChanges(&n)); 289*b39297aeSTomoki Sekiyama chk(pObj->get_Key(&key)); 290*b39297aeSTomoki Sekiyama 291*b39297aeSTomoki Sekiyama /* Setup users in the role */ 292*b39297aeSTomoki Sekiyama 293*b39297aeSTomoki Sekiyama chk(pRoles->GetCollection(_bstr_t(L"UsersInRole"), key, 294*b39297aeSTomoki Sekiyama (IDispatch **)pUsersInRole.replace())); 295*b39297aeSTomoki Sekiyama chk(pUsersInRole->Populate()); 296*b39297aeSTomoki Sekiyama 297*b39297aeSTomoki Sekiyama chk(pUsersInRole->Add((IDispatch **)pObj.replace())); 298*b39297aeSTomoki Sekiyama chk(GetAdminName(&name)); 299*b39297aeSTomoki Sekiyama chk(put_Value(pObj, L"User", _bstr_t(".\\") + name)); 300*b39297aeSTomoki Sekiyama 301*b39297aeSTomoki Sekiyama chk(pUsersInRole->Add((IDispatch **)pObj.replace())); 302*b39297aeSTomoki Sekiyama chk(put_Value(pObj, L"User", L"SYSTEM")); 303*b39297aeSTomoki Sekiyama chk(pUsersInRole->SaveChanges(&n)); 304*b39297aeSTomoki Sekiyama 305*b39297aeSTomoki Sekiyama out: 306*b39297aeSTomoki Sekiyama if (unregisterOnFailure && FAILED(hr)) { 307*b39297aeSTomoki Sekiyama COMUnregister(); 308*b39297aeSTomoki Sekiyama } 309*b39297aeSTomoki Sekiyama 310*b39297aeSTomoki Sekiyama return hr; 311*b39297aeSTomoki Sekiyama } 312*b39297aeSTomoki Sekiyama 313*b39297aeSTomoki Sekiyama 314*b39297aeSTomoki Sekiyama static BOOL CreateRegistryKey(LPCTSTR key, LPCTSTR value, LPCTSTR data) 315*b39297aeSTomoki Sekiyama { 316*b39297aeSTomoki Sekiyama HKEY hKey; 317*b39297aeSTomoki Sekiyama LONG ret; 318*b39297aeSTomoki Sekiyama DWORD size; 319*b39297aeSTomoki Sekiyama 320*b39297aeSTomoki Sekiyama ret = RegCreateKeyEx(HKEY_CLASSES_ROOT, key, 0, NULL, 321*b39297aeSTomoki Sekiyama REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL); 322*b39297aeSTomoki Sekiyama if (ret != ERROR_SUCCESS) { 323*b39297aeSTomoki Sekiyama goto out; 324*b39297aeSTomoki Sekiyama } 325*b39297aeSTomoki Sekiyama 326*b39297aeSTomoki Sekiyama if (data != NULL) { 327*b39297aeSTomoki Sekiyama size = strlen(data) + 1; 328*b39297aeSTomoki Sekiyama } else { 329*b39297aeSTomoki Sekiyama size = 0; 330*b39297aeSTomoki Sekiyama } 331*b39297aeSTomoki Sekiyama 332*b39297aeSTomoki Sekiyama ret = RegSetValueEx(hKey, value, 0, REG_SZ, (LPBYTE)data, size); 333*b39297aeSTomoki Sekiyama RegCloseKey(hKey); 334*b39297aeSTomoki Sekiyama 335*b39297aeSTomoki Sekiyama out: 336*b39297aeSTomoki Sekiyama if (ret != ERROR_SUCCESS) { 337*b39297aeSTomoki Sekiyama /* As we cannot printf within DllRegisterServer(), show a dialog. */ 338*b39297aeSTomoki Sekiyama errmsg_dialog(ret, "Cannot add registry", key); 339*b39297aeSTomoki Sekiyama return FALSE; 340*b39297aeSTomoki Sekiyama } 341*b39297aeSTomoki Sekiyama return TRUE; 342*b39297aeSTomoki Sekiyama } 343*b39297aeSTomoki Sekiyama 344*b39297aeSTomoki Sekiyama /* Register this dll as a VSS provider */ 345*b39297aeSTomoki Sekiyama STDAPI DllRegisterServer(void) 346*b39297aeSTomoki Sekiyama { 347*b39297aeSTomoki Sekiyama COMInitializer initializer; 348*b39297aeSTomoki Sekiyama COMPointer<IVssAdmin> pVssAdmin; 349*b39297aeSTomoki Sekiyama HRESULT hr = E_FAIL; 350*b39297aeSTomoki Sekiyama char dllPath[MAX_PATH]; 351*b39297aeSTomoki Sekiyama char key[256]; 352*b39297aeSTomoki Sekiyama 353*b39297aeSTomoki Sekiyama if (!g_hinstDll) { 354*b39297aeSTomoki Sekiyama errmsg_dialog(hr, "Module instance is not available"); 355*b39297aeSTomoki Sekiyama goto out; 356*b39297aeSTomoki Sekiyama } 357*b39297aeSTomoki Sekiyama 358*b39297aeSTomoki Sekiyama /* Add this module to registery */ 359*b39297aeSTomoki Sekiyama 360*b39297aeSTomoki Sekiyama sprintf(key, "CLSID\\%s", g_szClsid); 361*b39297aeSTomoki Sekiyama if (!CreateRegistryKey(key, NULL, g_szClsid)) { 362*b39297aeSTomoki Sekiyama goto out; 363*b39297aeSTomoki Sekiyama } 364*b39297aeSTomoki Sekiyama 365*b39297aeSTomoki Sekiyama if (!GetModuleFileName(g_hinstDll, dllPath, sizeof(dllPath))) { 366*b39297aeSTomoki Sekiyama errmsg_dialog(GetLastError(), "GetModuleFileName failed"); 367*b39297aeSTomoki Sekiyama goto out; 368*b39297aeSTomoki Sekiyama } 369*b39297aeSTomoki Sekiyama 370*b39297aeSTomoki Sekiyama sprintf(key, "CLSID\\%s\\InprocServer32", g_szClsid); 371*b39297aeSTomoki Sekiyama if (!CreateRegistryKey(key, NULL, dllPath)) { 372*b39297aeSTomoki Sekiyama goto out; 373*b39297aeSTomoki Sekiyama } 374*b39297aeSTomoki Sekiyama 375*b39297aeSTomoki Sekiyama if (!CreateRegistryKey(key, "ThreadingModel", "Apartment")) { 376*b39297aeSTomoki Sekiyama goto out; 377*b39297aeSTomoki Sekiyama } 378*b39297aeSTomoki Sekiyama 379*b39297aeSTomoki Sekiyama sprintf(key, "CLSID\\%s\\ProgID", g_szClsid); 380*b39297aeSTomoki Sekiyama if (!CreateRegistryKey(key, NULL, g_szProgid)) { 381*b39297aeSTomoki Sekiyama goto out; 382*b39297aeSTomoki Sekiyama } 383*b39297aeSTomoki Sekiyama 384*b39297aeSTomoki Sekiyama if (!CreateRegistryKey(g_szProgid, NULL, QGA_PROVIDER_NAME)) { 385*b39297aeSTomoki Sekiyama goto out; 386*b39297aeSTomoki Sekiyama } 387*b39297aeSTomoki Sekiyama 388*b39297aeSTomoki Sekiyama sprintf(key, "%s\\CLSID", g_szProgid); 389*b39297aeSTomoki Sekiyama if (!CreateRegistryKey(key, NULL, g_szClsid)) { 390*b39297aeSTomoki Sekiyama goto out; 391*b39297aeSTomoki Sekiyama } 392*b39297aeSTomoki Sekiyama 393*b39297aeSTomoki Sekiyama hr = CoCreateInstance(CLSID_VSSCoordinator, NULL, CLSCTX_ALL, 394*b39297aeSTomoki Sekiyama IID_IVssAdmin, (void **)pVssAdmin.replace()); 395*b39297aeSTomoki Sekiyama if (FAILED(hr)) { 396*b39297aeSTomoki Sekiyama errmsg_dialog(hr, "CoCreateInstance(VSSCoordinator) failed"); 397*b39297aeSTomoki Sekiyama goto out; 398*b39297aeSTomoki Sekiyama } 399*b39297aeSTomoki Sekiyama 400*b39297aeSTomoki Sekiyama hr = pVssAdmin->RegisterProvider(g_gProviderId, CLSID_QGAVSSProvider, 401*b39297aeSTomoki Sekiyama const_cast<WCHAR*>(QGA_PROVIDER_LNAME), 402*b39297aeSTomoki Sekiyama VSS_PROV_SOFTWARE, 403*b39297aeSTomoki Sekiyama const_cast<WCHAR*>(QGA_PROVIDER_VERSION), 404*b39297aeSTomoki Sekiyama g_gProviderVersion); 405*b39297aeSTomoki Sekiyama if (FAILED(hr)) { 406*b39297aeSTomoki Sekiyama errmsg_dialog(hr, "RegisterProvider failed"); 407*b39297aeSTomoki Sekiyama } 408*b39297aeSTomoki Sekiyama 409*b39297aeSTomoki Sekiyama out: 410*b39297aeSTomoki Sekiyama if (FAILED(hr)) { 411*b39297aeSTomoki Sekiyama DllUnregisterServer(); 412*b39297aeSTomoki Sekiyama } 413*b39297aeSTomoki Sekiyama 414*b39297aeSTomoki Sekiyama return hr; 415*b39297aeSTomoki Sekiyama } 416*b39297aeSTomoki Sekiyama 417*b39297aeSTomoki Sekiyama /* Unregister this VSS hardware provider from the system */ 418*b39297aeSTomoki Sekiyama STDAPI DllUnregisterServer(void) 419*b39297aeSTomoki Sekiyama { 420*b39297aeSTomoki Sekiyama TCHAR key[256]; 421*b39297aeSTomoki Sekiyama COMInitializer initializer; 422*b39297aeSTomoki Sekiyama COMPointer<IVssAdmin> pVssAdmin; 423*b39297aeSTomoki Sekiyama 424*b39297aeSTomoki Sekiyama HRESULT hr = CoCreateInstance(CLSID_VSSCoordinator, 425*b39297aeSTomoki Sekiyama NULL, CLSCTX_ALL, IID_IVssAdmin, 426*b39297aeSTomoki Sekiyama (void **)pVssAdmin.replace()); 427*b39297aeSTomoki Sekiyama if (SUCCEEDED(hr)) { 428*b39297aeSTomoki Sekiyama hr = pVssAdmin->UnregisterProvider(g_gProviderId); 429*b39297aeSTomoki Sekiyama } else { 430*b39297aeSTomoki Sekiyama errmsg(hr, "CoCreateInstance(VSSCoordinator) failed"); 431*b39297aeSTomoki Sekiyama } 432*b39297aeSTomoki Sekiyama 433*b39297aeSTomoki Sekiyama sprintf(key, "CLSID\\%s", g_szClsid); 434*b39297aeSTomoki Sekiyama SHDeleteKey(HKEY_CLASSES_ROOT, key); 435*b39297aeSTomoki Sekiyama SHDeleteKey(HKEY_CLASSES_ROOT, g_szProgid); 436*b39297aeSTomoki Sekiyama 437*b39297aeSTomoki Sekiyama return S_OK; /* Uninstall should never fail */ 438*b39297aeSTomoki Sekiyama } 439*b39297aeSTomoki Sekiyama 440*b39297aeSTomoki Sekiyama 441*b39297aeSTomoki Sekiyama /* Support function to convert ASCII string into BSTR (used in _bstr_t) */ 442*b39297aeSTomoki Sekiyama namespace _com_util 443*b39297aeSTomoki Sekiyama { 444*b39297aeSTomoki Sekiyama BSTR WINAPI ConvertStringToBSTR(const char *ascii) { 445*b39297aeSTomoki Sekiyama int len = strlen(ascii); 446*b39297aeSTomoki Sekiyama BSTR bstr = SysAllocStringLen(NULL, len); 447*b39297aeSTomoki Sekiyama 448*b39297aeSTomoki Sekiyama if (!bstr) { 449*b39297aeSTomoki Sekiyama return NULL; 450*b39297aeSTomoki Sekiyama } 451*b39297aeSTomoki Sekiyama 452*b39297aeSTomoki Sekiyama if (mbstowcs(bstr, ascii, len) == (size_t)-1) { 453*b39297aeSTomoki Sekiyama fprintf(stderr, "Failed to convert string '%s' into BSTR", ascii); 454*b39297aeSTomoki Sekiyama bstr[0] = 0; 455*b39297aeSTomoki Sekiyama } 456*b39297aeSTomoki Sekiyama return bstr; 457*b39297aeSTomoki Sekiyama } 458*b39297aeSTomoki Sekiyama } 459