xref: /openbmc/qemu/qga/vss-win32/install.cpp (revision 622b0efa377434fc12364e5290d14665fe5d2d52)
1b39297aeSTomoki Sekiyama /*
2b39297aeSTomoki Sekiyama  * QEMU Guest Agent win32 VSS Provider installer
3b39297aeSTomoki Sekiyama  *
4b39297aeSTomoki Sekiyama  * Copyright Hitachi Data Systems Corp. 2013
5b39297aeSTomoki Sekiyama  *
6b39297aeSTomoki Sekiyama  * Authors:
7b39297aeSTomoki Sekiyama  *  Tomoki Sekiyama   <tomoki.sekiyama@hds.com>
8b39297aeSTomoki Sekiyama  *
9b39297aeSTomoki Sekiyama  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10b39297aeSTomoki Sekiyama  * See the COPYING file in the top-level directory.
11b39297aeSTomoki Sekiyama  */
12b39297aeSTomoki Sekiyama 
13e55eb806SMichael Roth #include "qemu/osdep.h"
14b39297aeSTomoki Sekiyama 
15b39297aeSTomoki Sekiyama #include "vss-common.h"
162f84cf69SKonstantin Kostiuk #include "vss-debug.h"
17872b69e6SMarc-André Lureau #ifdef HAVE_VSS_SDK
1861fb0bd1SMarc-André Lureau #include <vscoordint.h>
19872b69e6SMarc-André Lureau #else
20872b69e6SMarc-André Lureau #include <vsadmin.h>
21872b69e6SMarc-André Lureau #endif
22f342cc93SSameeh Jubran #include "install.h"
23b39297aeSTomoki Sekiyama #include <wbemidl.h>
24b39297aeSTomoki Sekiyama #include <comdef.h>
25b39297aeSTomoki Sekiyama #include <comutil.h>
26009f38d9SDaniel Rempel #include <sddl.h>
27917ebcb1SBasil Salman #include <winsvc.h>
28009f38d9SDaniel Rempel 
29009f38d9SDaniel Rempel #define BUFFER_SIZE 1024
30b39297aeSTomoki Sekiyama 
31b39297aeSTomoki Sekiyama extern HINSTANCE g_hinstDll;
32b39297aeSTomoki Sekiyama 
33b39297aeSTomoki Sekiyama const GUID CLSID_COMAdminCatalog = { 0xF618C514, 0xDFB8, 0x11d1,
34b39297aeSTomoki Sekiyama     {0xA2, 0xCF, 0x00, 0x80, 0x5F, 0xC7, 0x92, 0x35} };
35bca4bf10STomoki Sekiyama const GUID IID_ICOMAdminCatalog2 = { 0x790C6E0B, 0x9194, 0x4cc9,
36bca4bf10STomoki Sekiyama     {0x94, 0x26, 0xA4, 0x8A, 0x63, 0x18, 0x56, 0x96} };
37b39297aeSTomoki Sekiyama const GUID CLSID_WbemLocator = { 0x4590f811, 0x1d3a, 0x11d0,
38b39297aeSTomoki Sekiyama     {0x89, 0x1f, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24} };
39b39297aeSTomoki Sekiyama const GUID IID_IWbemLocator = { 0xdc12a687, 0x737f, 0x11cf,
40b39297aeSTomoki Sekiyama     {0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24} };
41b39297aeSTomoki Sekiyama 
errmsg(DWORD err,const char * text)42*73aaabcfSPierrick Bouvier static void errmsg(DWORD err, const char *text)
43b39297aeSTomoki Sekiyama {
44b39297aeSTomoki Sekiyama     /*
45b39297aeSTomoki Sekiyama      * `text' contains function call statement when errmsg is called via chk().
46b39297aeSTomoki Sekiyama      * To make error message more readable, we cut off the text after '('.
47b39297aeSTomoki Sekiyama      * If text doesn't contains '(', negative precision is given, which is
48b39297aeSTomoki Sekiyama      * treated as though it were missing.
49b39297aeSTomoki Sekiyama      */
507bd16378SHelge Konetzka     char *msg = NULL;
517bd16378SHelge Konetzka     const char *nul = strchr(text, '(');
52b39297aeSTomoki Sekiyama     int len = nul ? nul - text : -1;
53b39297aeSTomoki Sekiyama 
54b39297aeSTomoki Sekiyama     FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
55b39297aeSTomoki Sekiyama                   FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
56b39297aeSTomoki Sekiyama                   NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
57b39297aeSTomoki Sekiyama                   (char *)&msg, 0, NULL);
582f84cf69SKonstantin Kostiuk     qga_debug("%.*s. (Error: %lx) %s", len, text, err, msg);
59b39297aeSTomoki Sekiyama     LocalFree(msg);
60b39297aeSTomoki Sekiyama }
61b39297aeSTomoki Sekiyama 
errmsg_dialog(DWORD err,const char * text,const char * opt="")62b39297aeSTomoki Sekiyama static void errmsg_dialog(DWORD err, const char *text, const char *opt = "")
63b39297aeSTomoki Sekiyama {
64b39297aeSTomoki Sekiyama     char *msg, buf[512];
65b39297aeSTomoki Sekiyama 
66b39297aeSTomoki Sekiyama     FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
67b39297aeSTomoki Sekiyama                   FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
68b39297aeSTomoki Sekiyama                   NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
69b39297aeSTomoki Sekiyama                   (char *)&msg, 0, NULL);
70b39297aeSTomoki Sekiyama     snprintf(buf, sizeof(buf), "%s%s. (Error: %lx) %s", text, opt, err, msg);
71b39297aeSTomoki Sekiyama     MessageBox(NULL, buf, "Error from " QGA_PROVIDER_NAME, MB_OK|MB_ICONERROR);
72b39297aeSTomoki Sekiyama     LocalFree(msg);
73b39297aeSTomoki Sekiyama }
74b39297aeSTomoki Sekiyama 
75b39297aeSTomoki Sekiyama #define _chk(hr, status, msg, err_label)        \
76b39297aeSTomoki Sekiyama     do {                                        \
77b39297aeSTomoki Sekiyama         hr = (status);                          \
78b39297aeSTomoki Sekiyama         if (FAILED(hr)) {                       \
79b39297aeSTomoki Sekiyama             errmsg(hr, msg);                    \
80b39297aeSTomoki Sekiyama             goto err_label;                     \
81b39297aeSTomoki Sekiyama         }                                       \
82b39297aeSTomoki Sekiyama     } while (0)
83b39297aeSTomoki Sekiyama 
84b39297aeSTomoki Sekiyama #define chk(status) _chk(hr, status, "Failed to " #status, out)
85b39297aeSTomoki Sekiyama 
869854202bSTomoki Sekiyama #if !defined(__MINGW64_VERSION_MAJOR) || !defined(__MINGW64_VERSION_MINOR) || \
879854202bSTomoki Sekiyama     __MINGW64_VERSION_MAJOR * 100 + __MINGW64_VERSION_MINOR < 301
_com_issue_error(HRESULT hr)88b39297aeSTomoki Sekiyama void __stdcall _com_issue_error(HRESULT hr)
89b39297aeSTomoki Sekiyama {
90b39297aeSTomoki Sekiyama     errmsg(hr, "Unexpected error in COM");
91b39297aeSTomoki Sekiyama }
929854202bSTomoki Sekiyama #endif
93b39297aeSTomoki Sekiyama 
94b39297aeSTomoki Sekiyama template<class T>
put_Value(ICatalogObject * pObj,LPCWSTR name,T val)95b39297aeSTomoki Sekiyama HRESULT put_Value(ICatalogObject *pObj, LPCWSTR name, T val)
96b39297aeSTomoki Sekiyama {
97b39297aeSTomoki Sekiyama     return pObj->put_Value(_bstr_t(name), _variant_t(val));
98b39297aeSTomoki Sekiyama }
99b39297aeSTomoki Sekiyama 
100b39297aeSTomoki Sekiyama /* Lookup Administrators group name from winmgmt */
GetAdminName(_bstr_t * name)101b39297aeSTomoki Sekiyama static HRESULT GetAdminName(_bstr_t *name)
102b39297aeSTomoki Sekiyama {
10361df91b3SKonstantin Kostiuk     qga_debug_begin;
10461df91b3SKonstantin Kostiuk 
105b39297aeSTomoki Sekiyama     HRESULT hr;
106b39297aeSTomoki Sekiyama     COMPointer<IWbemLocator> pLoc;
107b39297aeSTomoki Sekiyama     COMPointer<IWbemServices> pSvc;
108b39297aeSTomoki Sekiyama     COMPointer<IEnumWbemClassObject> pEnum;
109b39297aeSTomoki Sekiyama     COMPointer<IWbemClassObject> pWobj;
110b39297aeSTomoki Sekiyama     ULONG returned;
111b39297aeSTomoki Sekiyama     _variant_t var;
112b39297aeSTomoki Sekiyama 
113b39297aeSTomoki Sekiyama     chk(CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER,
114b39297aeSTomoki Sekiyama                          IID_IWbemLocator, (LPVOID *)pLoc.replace()));
115b39297aeSTomoki Sekiyama     chk(pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), NULL, NULL, NULL,
116b39297aeSTomoki Sekiyama                             0, 0, 0, pSvc.replace()));
117b39297aeSTomoki Sekiyama     chk(CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
118b39297aeSTomoki Sekiyama                           NULL, RPC_C_AUTHN_LEVEL_CALL,
119b39297aeSTomoki Sekiyama                           RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE));
120b39297aeSTomoki Sekiyama     chk(pSvc->ExecQuery(_bstr_t(L"WQL"),
121b39297aeSTomoki Sekiyama                         _bstr_t(L"select * from Win32_Account where "
122b39297aeSTomoki Sekiyama                                 "SID='S-1-5-32-544' and localAccount=TRUE"),
123b39297aeSTomoki Sekiyama                         WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
124b39297aeSTomoki Sekiyama                         NULL, pEnum.replace()));
125b39297aeSTomoki Sekiyama     if (!pEnum) {
126b39297aeSTomoki Sekiyama         hr = E_FAIL;
127b39297aeSTomoki Sekiyama         errmsg(hr, "Failed to query for Administrators");
128b39297aeSTomoki Sekiyama         goto out;
129b39297aeSTomoki Sekiyama     }
130b39297aeSTomoki Sekiyama     chk(pEnum->Next(WBEM_INFINITE, 1, pWobj.replace(), &returned));
131b39297aeSTomoki Sekiyama     if (returned == 0) {
132b39297aeSTomoki Sekiyama         hr = E_FAIL;
133b39297aeSTomoki Sekiyama         errmsg(hr, "No Administrators found");
134b39297aeSTomoki Sekiyama         goto out;
135b39297aeSTomoki Sekiyama     }
136b39297aeSTomoki Sekiyama 
137b39297aeSTomoki Sekiyama     chk(pWobj->Get(_bstr_t(L"Name"), 0, &var, 0, 0));
138b39297aeSTomoki Sekiyama     try {
139b39297aeSTomoki Sekiyama         *name = var;
140b39297aeSTomoki Sekiyama     } catch(...) {
141b39297aeSTomoki Sekiyama         hr = E_FAIL;
142b39297aeSTomoki Sekiyama         errmsg(hr, "Failed to get name of Administrators");
143b39297aeSTomoki Sekiyama         goto out;
144b39297aeSTomoki Sekiyama     }
145b39297aeSTomoki Sekiyama 
146b39297aeSTomoki Sekiyama out:
14761df91b3SKonstantin Kostiuk     qga_debug_end;
148b39297aeSTomoki Sekiyama     return hr;
149b39297aeSTomoki Sekiyama }
150b39297aeSTomoki Sekiyama 
151009f38d9SDaniel Rempel /* Acquire group or user name by SID */
getNameByStringSID(const wchar_t * sid,LPWSTR buffer,LPDWORD bufferLen)152009f38d9SDaniel Rempel static HRESULT getNameByStringSID(
153009f38d9SDaniel Rempel     const wchar_t *sid, LPWSTR buffer, LPDWORD bufferLen)
154009f38d9SDaniel Rempel {
15561df91b3SKonstantin Kostiuk     qga_debug_begin;
15661df91b3SKonstantin Kostiuk 
157009f38d9SDaniel Rempel     HRESULT hr = S_OK;
158009f38d9SDaniel Rempel     PSID psid = NULL;
159009f38d9SDaniel Rempel     SID_NAME_USE groupType;
160009f38d9SDaniel Rempel     DWORD domainNameLen = BUFFER_SIZE;
161009f38d9SDaniel Rempel     wchar_t domainName[BUFFER_SIZE];
162009f38d9SDaniel Rempel 
1638cedc805SMichael Roth     if (!ConvertStringSidToSidW(sid, &psid)) {
164009f38d9SDaniel Rempel         hr = HRESULT_FROM_WIN32(GetLastError());
1658cedc805SMichael Roth         goto out;
1668cedc805SMichael Roth     }
1678cedc805SMichael Roth     if (!LookupAccountSidW(NULL, psid, buffer, bufferLen,
1688cedc805SMichael Roth                            domainName, &domainNameLen, &groupType)) {
1698cedc805SMichael Roth         hr = HRESULT_FROM_WIN32(GetLastError());
1708cedc805SMichael Roth         /* Fall through and free psid */
1718cedc805SMichael Roth     }
172009f38d9SDaniel Rempel 
173009f38d9SDaniel Rempel     LocalFree(psid);
174009f38d9SDaniel Rempel 
175009f38d9SDaniel Rempel out:
17661df91b3SKonstantin Kostiuk     qga_debug_end;
177009f38d9SDaniel Rempel     return hr;
178009f38d9SDaniel Rempel }
179009f38d9SDaniel Rempel 
180b39297aeSTomoki Sekiyama /* Find and iterate QGA VSS provider in COM+ Application Catalog */
QGAProviderFind(HRESULT (* found)(ICatalogCollection *,int,void *),void * arg)181b39297aeSTomoki Sekiyama static HRESULT QGAProviderFind(
182b39297aeSTomoki Sekiyama     HRESULT (*found)(ICatalogCollection *, int, void *), void *arg)
183b39297aeSTomoki Sekiyama {
18461df91b3SKonstantin Kostiuk     qga_debug_begin;
18561df91b3SKonstantin Kostiuk 
186b39297aeSTomoki Sekiyama     HRESULT hr;
187b39297aeSTomoki Sekiyama     COMInitializer initializer;
188b39297aeSTomoki Sekiyama     COMPointer<IUnknown> pUnknown;
189bca4bf10STomoki Sekiyama     COMPointer<ICOMAdminCatalog2> pCatalog;
190b39297aeSTomoki Sekiyama     COMPointer<ICatalogCollection> pColl;
191b39297aeSTomoki Sekiyama     COMPointer<ICatalogObject> pObj;
192b39297aeSTomoki Sekiyama     _variant_t var;
193b39297aeSTomoki Sekiyama     long i, n;
194b39297aeSTomoki Sekiyama 
195b39297aeSTomoki Sekiyama     chk(CoCreateInstance(CLSID_COMAdminCatalog, NULL, CLSCTX_INPROC_SERVER,
196b39297aeSTomoki Sekiyama                          IID_IUnknown, (void **)pUnknown.replace()));
197bca4bf10STomoki Sekiyama     chk(pUnknown->QueryInterface(IID_ICOMAdminCatalog2,
198b39297aeSTomoki Sekiyama                                  (void **)pCatalog.replace()));
199b39297aeSTomoki Sekiyama     chk(pCatalog->GetCollection(_bstr_t(L"Applications"),
200b39297aeSTomoki Sekiyama                                 (IDispatch **)pColl.replace()));
201b39297aeSTomoki Sekiyama     chk(pColl->Populate());
202b39297aeSTomoki Sekiyama 
203b39297aeSTomoki Sekiyama     chk(pColl->get_Count(&n));
204b39297aeSTomoki Sekiyama     for (i = n - 1; i >= 0; i--) {
205b39297aeSTomoki Sekiyama         chk(pColl->get_Item(i, (IDispatch **)pObj.replace()));
206b39297aeSTomoki Sekiyama         chk(pObj->get_Value(_bstr_t(L"Name"), &var));
207b39297aeSTomoki Sekiyama         if (var == _variant_t(QGA_PROVIDER_LNAME)) {
208b39297aeSTomoki Sekiyama             if (FAILED(found(pColl, i, arg))) {
209b39297aeSTomoki Sekiyama                 goto out;
210b39297aeSTomoki Sekiyama             }
211b39297aeSTomoki Sekiyama         }
212b39297aeSTomoki Sekiyama     }
213b39297aeSTomoki Sekiyama     chk(pColl->SaveChanges(&n));
214b39297aeSTomoki Sekiyama 
215b39297aeSTomoki Sekiyama out:
21661df91b3SKonstantin Kostiuk     qga_debug_end;
217b39297aeSTomoki Sekiyama     return hr;
218b39297aeSTomoki Sekiyama }
219b39297aeSTomoki Sekiyama 
220b39297aeSTomoki Sekiyama /* Count QGA VSS provider in COM+ Application Catalog */
QGAProviderCount(ICatalogCollection * coll,int i,void * arg)221b39297aeSTomoki Sekiyama static HRESULT QGAProviderCount(ICatalogCollection *coll, int i, void *arg)
222b39297aeSTomoki Sekiyama {
22361df91b3SKonstantin Kostiuk     qga_debug_begin;
22461df91b3SKonstantin Kostiuk 
225b39297aeSTomoki Sekiyama     (*(int *)arg)++;
22661df91b3SKonstantin Kostiuk 
22761df91b3SKonstantin Kostiuk     qga_debug_end;
228b39297aeSTomoki Sekiyama     return S_OK;
229b39297aeSTomoki Sekiyama }
230b39297aeSTomoki Sekiyama 
231b39297aeSTomoki Sekiyama /* Remove QGA VSS provider from COM+ Application Catalog Collection */
QGAProviderRemove(ICatalogCollection * coll,int i,void * arg)232b39297aeSTomoki Sekiyama static HRESULT QGAProviderRemove(ICatalogCollection *coll, int i, void *arg)
233b39297aeSTomoki Sekiyama {
23461df91b3SKonstantin Kostiuk     qga_debug_begin;
235b39297aeSTomoki Sekiyama     HRESULT hr;
236b39297aeSTomoki Sekiyama 
2372f84cf69SKonstantin Kostiuk     qga_debug("Removing COM+ Application: %s", QGA_PROVIDER_NAME);
238b39297aeSTomoki Sekiyama     chk(coll->Remove(i));
239b39297aeSTomoki Sekiyama out:
24061df91b3SKonstantin Kostiuk     qga_debug_end;
241b39297aeSTomoki Sekiyama     return hr;
242b39297aeSTomoki Sekiyama }
243b39297aeSTomoki Sekiyama 
244b39297aeSTomoki Sekiyama /* Unregister this module from COM+ Applications Catalog */
245*73aaabcfSPierrick Bouvier STDAPI COMUnregister(void);
COMUnregister(void)246b39297aeSTomoki Sekiyama STDAPI COMUnregister(void)
247b39297aeSTomoki Sekiyama {
24861df91b3SKonstantin Kostiuk     qga_debug_begin;
24961df91b3SKonstantin Kostiuk 
250b39297aeSTomoki Sekiyama     HRESULT hr;
251b39297aeSTomoki Sekiyama 
252b39297aeSTomoki Sekiyama     DllUnregisterServer();
253b39297aeSTomoki Sekiyama     chk(QGAProviderFind(QGAProviderRemove, NULL));
254b39297aeSTomoki Sekiyama out:
25561df91b3SKonstantin Kostiuk     qga_debug_end;
256b39297aeSTomoki Sekiyama     return hr;
257b39297aeSTomoki Sekiyama }
258b39297aeSTomoki Sekiyama 
259b39297aeSTomoki Sekiyama /* Register this module to COM+ Applications Catalog */
260*73aaabcfSPierrick Bouvier STDAPI COMRegister(void);
COMRegister(void)261b39297aeSTomoki Sekiyama STDAPI COMRegister(void)
262b39297aeSTomoki Sekiyama {
26361df91b3SKonstantin Kostiuk     qga_debug_begin;
26461df91b3SKonstantin Kostiuk 
265b39297aeSTomoki Sekiyama     HRESULT hr;
266b39297aeSTomoki Sekiyama     COMInitializer initializer;
267b39297aeSTomoki Sekiyama     COMPointer<IUnknown> pUnknown;
268bca4bf10STomoki Sekiyama     COMPointer<ICOMAdminCatalog2> pCatalog;
269b39297aeSTomoki Sekiyama     COMPointer<ICatalogCollection> pApps, pRoles, pUsersInRole;
270b39297aeSTomoki Sekiyama     COMPointer<ICatalogObject> pObj;
271b39297aeSTomoki Sekiyama     long n;
272b39297aeSTomoki Sekiyama     _bstr_t name;
273b39297aeSTomoki Sekiyama     _variant_t key;
274b39297aeSTomoki Sekiyama     CHAR dllPath[MAX_PATH], tlbPath[MAX_PATH];
275b39297aeSTomoki Sekiyama     bool unregisterOnFailure = false;
276b39297aeSTomoki Sekiyama     int count = 0;
277009f38d9SDaniel Rempel     DWORD bufferLen = BUFFER_SIZE;
278009f38d9SDaniel Rempel     wchar_t buffer[BUFFER_SIZE];
279009f38d9SDaniel Rempel     const wchar_t *administratorsGroupSID = L"S-1-5-32-544";
280009f38d9SDaniel Rempel     const wchar_t *systemUserSID = L"S-1-5-18";
281b39297aeSTomoki Sekiyama 
282b39297aeSTomoki Sekiyama     if (!g_hinstDll) {
283b39297aeSTomoki Sekiyama         errmsg(E_FAIL, "Failed to initialize DLL");
28461df91b3SKonstantin Kostiuk         qga_debug_end;
285b39297aeSTomoki Sekiyama         return E_FAIL;
286b39297aeSTomoki Sekiyama     }
287b39297aeSTomoki Sekiyama 
288b39297aeSTomoki Sekiyama     chk(QGAProviderFind(QGAProviderCount, (void *)&count));
289b39297aeSTomoki Sekiyama     if (count) {
290b39297aeSTomoki Sekiyama         errmsg(E_ABORT, "QGA VSS Provider is already installed");
29161df91b3SKonstantin Kostiuk         qga_debug_end;
292b39297aeSTomoki Sekiyama         return E_ABORT;
293b39297aeSTomoki Sekiyama     }
294b39297aeSTomoki Sekiyama 
295b39297aeSTomoki Sekiyama     chk(CoCreateInstance(CLSID_COMAdminCatalog, NULL, CLSCTX_INPROC_SERVER,
296b39297aeSTomoki Sekiyama                          IID_IUnknown, (void **)pUnknown.replace()));
297bca4bf10STomoki Sekiyama     chk(pUnknown->QueryInterface(IID_ICOMAdminCatalog2,
298b39297aeSTomoki Sekiyama                                  (void **)pCatalog.replace()));
299b39297aeSTomoki Sekiyama 
300b39297aeSTomoki Sekiyama     /* Install COM+ Component */
301b39297aeSTomoki Sekiyama 
302b39297aeSTomoki Sekiyama     chk(pCatalog->GetCollection(_bstr_t(L"Applications"),
303b39297aeSTomoki Sekiyama                                 (IDispatch **)pApps.replace()));
304b39297aeSTomoki Sekiyama     chk(pApps->Populate());
305b39297aeSTomoki Sekiyama     chk(pApps->Add((IDispatch **)&pObj));
306b39297aeSTomoki Sekiyama     chk(put_Value(pObj, L"Name",        QGA_PROVIDER_LNAME));
307b39297aeSTomoki Sekiyama     chk(put_Value(pObj, L"Description", QGA_PROVIDER_LNAME));
308b39297aeSTomoki Sekiyama     chk(put_Value(pObj, L"ApplicationAccessChecksEnabled", true));
309b39297aeSTomoki Sekiyama     chk(put_Value(pObj, L"Authentication",                 short(6)));
310b39297aeSTomoki Sekiyama     chk(put_Value(pObj, L"AuthenticationCapability",       short(2)));
311b39297aeSTomoki Sekiyama     chk(put_Value(pObj, L"ImpersonationLevel",             short(2)));
312b39297aeSTomoki Sekiyama     chk(pApps->SaveChanges(&n));
313b39297aeSTomoki Sekiyama 
314b39297aeSTomoki Sekiyama     /* The app should be deleted if something fails after SaveChanges */
315b39297aeSTomoki Sekiyama     unregisterOnFailure = true;
316b39297aeSTomoki Sekiyama 
317b39297aeSTomoki Sekiyama     chk(pObj->get_Key(&key));
318b39297aeSTomoki Sekiyama 
319b39297aeSTomoki Sekiyama     if (!GetModuleFileName(g_hinstDll, dllPath, sizeof(dllPath))) {
320b39297aeSTomoki Sekiyama         hr = HRESULT_FROM_WIN32(GetLastError());
321b39297aeSTomoki Sekiyama         errmsg(hr, "GetModuleFileName failed");
322b39297aeSTomoki Sekiyama         goto out;
323b39297aeSTomoki Sekiyama     }
324b39297aeSTomoki Sekiyama     n = strlen(dllPath);
325b39297aeSTomoki Sekiyama     if (n < 3) {
326b39297aeSTomoki Sekiyama         hr = E_FAIL;
327b39297aeSTomoki Sekiyama         errmsg(hr, "Failed to lookup dll");
328b39297aeSTomoki Sekiyama         goto out;
329b39297aeSTomoki Sekiyama     }
330b39297aeSTomoki Sekiyama     strcpy(tlbPath, dllPath);
331b39297aeSTomoki Sekiyama     strcpy(tlbPath+n-3, "tlb");
3322f84cf69SKonstantin Kostiuk     qga_debug("Registering " QGA_PROVIDER_NAME ": %s %s",
3332f84cf69SKonstantin Kostiuk               dllPath, tlbPath);
334b39297aeSTomoki Sekiyama     if (!PathFileExists(tlbPath)) {
335b39297aeSTomoki Sekiyama         hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
336b39297aeSTomoki Sekiyama         errmsg(hr, "Failed to lookup tlb");
337b39297aeSTomoki Sekiyama         goto out;
338b39297aeSTomoki Sekiyama     }
339b39297aeSTomoki Sekiyama 
340bca4bf10STomoki Sekiyama     chk(pCatalog->CreateServiceForApplication(
341bca4bf10STomoki Sekiyama             _bstr_t(QGA_PROVIDER_LNAME), _bstr_t(QGA_PROVIDER_LNAME),
342f342cc93SSameeh Jubran             _bstr_t(L"SERVICE_DEMAND_START"), _bstr_t(L"SERVICE_ERROR_NORMAL"),
343bca4bf10STomoki Sekiyama             _bstr_t(L""), _bstr_t(L".\\localsystem"), _bstr_t(L""), FALSE));
344b39297aeSTomoki Sekiyama     chk(pCatalog->InstallComponent(_bstr_t(QGA_PROVIDER_LNAME),
345b39297aeSTomoki Sekiyama                                    _bstr_t(dllPath), _bstr_t(tlbPath),
346b39297aeSTomoki Sekiyama                                    _bstr_t("")));
347b39297aeSTomoki Sekiyama 
34801dc0651SMichael Tokarev     /* Setup roles of the application */
349b39297aeSTomoki Sekiyama 
350009f38d9SDaniel Rempel     chk(getNameByStringSID(administratorsGroupSID, buffer, &bufferLen));
351b39297aeSTomoki Sekiyama     chk(pApps->GetCollection(_bstr_t(L"Roles"), key,
352b39297aeSTomoki Sekiyama                              (IDispatch **)pRoles.replace()));
353b39297aeSTomoki Sekiyama     chk(pRoles->Populate());
354b39297aeSTomoki Sekiyama     chk(pRoles->Add((IDispatch **)pObj.replace()));
355009f38d9SDaniel Rempel     chk(put_Value(pObj, L"Name", buffer));
356b39297aeSTomoki Sekiyama     chk(put_Value(pObj, L"Description", L"Administrators group"));
357b39297aeSTomoki Sekiyama     chk(pRoles->SaveChanges(&n));
358b39297aeSTomoki Sekiyama     chk(pObj->get_Key(&key));
359b39297aeSTomoki Sekiyama 
360b39297aeSTomoki Sekiyama     /* Setup users in the role */
361b39297aeSTomoki Sekiyama 
362b39297aeSTomoki Sekiyama     chk(pRoles->GetCollection(_bstr_t(L"UsersInRole"), key,
363b39297aeSTomoki Sekiyama                               (IDispatch **)pUsersInRole.replace()));
364b39297aeSTomoki Sekiyama     chk(pUsersInRole->Populate());
365b39297aeSTomoki Sekiyama 
366b39297aeSTomoki Sekiyama     chk(pUsersInRole->Add((IDispatch **)pObj.replace()));
367b39297aeSTomoki Sekiyama     chk(GetAdminName(&name));
368b39297aeSTomoki Sekiyama     chk(put_Value(pObj, L"User", _bstr_t(".\\") + name));
369b39297aeSTomoki Sekiyama 
370009f38d9SDaniel Rempel     bufferLen = BUFFER_SIZE;
371009f38d9SDaniel Rempel     chk(getNameByStringSID(systemUserSID, buffer, &bufferLen));
372b39297aeSTomoki Sekiyama     chk(pUsersInRole->Add((IDispatch **)pObj.replace()));
373009f38d9SDaniel Rempel     chk(put_Value(pObj, L"User", buffer));
374b39297aeSTomoki Sekiyama     chk(pUsersInRole->SaveChanges(&n));
375b39297aeSTomoki Sekiyama 
376b39297aeSTomoki Sekiyama out:
377b39297aeSTomoki Sekiyama     if (unregisterOnFailure && FAILED(hr)) {
378b39297aeSTomoki Sekiyama         COMUnregister();
379b39297aeSTomoki Sekiyama     }
380b39297aeSTomoki Sekiyama 
38161df91b3SKonstantin Kostiuk     qga_debug_end;
382b39297aeSTomoki Sekiyama     return hr;
383b39297aeSTomoki Sekiyama }
384b39297aeSTomoki Sekiyama 
385*73aaabcfSPierrick Bouvier STDAPI_(void) CALLBACK DLLCOMRegister(HWND, HINSTANCE, LPSTR, int);
STDAPI_(void)38607ce178aSKonstantin Kostiuk STDAPI_(void) CALLBACK DLLCOMRegister(HWND, HINSTANCE, LPSTR, int)
38707ce178aSKonstantin Kostiuk {
38807ce178aSKonstantin Kostiuk     COMRegister();
38907ce178aSKonstantin Kostiuk }
39007ce178aSKonstantin Kostiuk 
391*73aaabcfSPierrick Bouvier STDAPI_(void) CALLBACK DLLCOMUnregister(HWND, HINSTANCE, LPSTR, int);
STDAPI_(void)39207ce178aSKonstantin Kostiuk STDAPI_(void) CALLBACK DLLCOMUnregister(HWND, HINSTANCE, LPSTR, int)
39307ce178aSKonstantin Kostiuk {
39407ce178aSKonstantin Kostiuk     COMUnregister();
39507ce178aSKonstantin Kostiuk }
396b39297aeSTomoki Sekiyama 
CreateRegistryKey(LPCTSTR key,LPCTSTR value,LPCTSTR data)397b39297aeSTomoki Sekiyama static BOOL CreateRegistryKey(LPCTSTR key, LPCTSTR value, LPCTSTR data)
398b39297aeSTomoki Sekiyama {
39961df91b3SKonstantin Kostiuk     qga_debug_begin;
40061df91b3SKonstantin Kostiuk 
401b39297aeSTomoki Sekiyama     HKEY  hKey;
402b39297aeSTomoki Sekiyama     LONG  ret;
403b39297aeSTomoki Sekiyama     DWORD size;
404b39297aeSTomoki Sekiyama 
405b39297aeSTomoki Sekiyama     ret = RegCreateKeyEx(HKEY_CLASSES_ROOT, key, 0, NULL,
406b39297aeSTomoki Sekiyama         REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL);
407b39297aeSTomoki Sekiyama     if (ret != ERROR_SUCCESS) {
408b39297aeSTomoki Sekiyama         goto out;
409b39297aeSTomoki Sekiyama     }
410b39297aeSTomoki Sekiyama 
411b39297aeSTomoki Sekiyama     if (data != NULL) {
412b39297aeSTomoki Sekiyama         size = strlen(data) + 1;
413b39297aeSTomoki Sekiyama     } else {
414b39297aeSTomoki Sekiyama         size = 0;
415b39297aeSTomoki Sekiyama     }
416b39297aeSTomoki Sekiyama 
417b39297aeSTomoki Sekiyama     ret = RegSetValueEx(hKey, value, 0, REG_SZ, (LPBYTE)data, size);
418b39297aeSTomoki Sekiyama     RegCloseKey(hKey);
419b39297aeSTomoki Sekiyama 
420b39297aeSTomoki Sekiyama out:
42161df91b3SKonstantin Kostiuk     qga_debug_end;
422b39297aeSTomoki Sekiyama     if (ret != ERROR_SUCCESS) {
423b39297aeSTomoki Sekiyama         /* As we cannot printf within DllRegisterServer(), show a dialog. */
424b39297aeSTomoki Sekiyama         errmsg_dialog(ret, "Cannot add registry", key);
425b39297aeSTomoki Sekiyama         return FALSE;
426b39297aeSTomoki Sekiyama     }
427b39297aeSTomoki Sekiyama     return TRUE;
428b39297aeSTomoki Sekiyama }
429b39297aeSTomoki Sekiyama 
430b39297aeSTomoki Sekiyama /* Register this dll as a VSS provider */
DllRegisterServer(void)431b39297aeSTomoki Sekiyama STDAPI DllRegisterServer(void)
432b39297aeSTomoki Sekiyama {
43361df91b3SKonstantin Kostiuk     qga_debug_begin;
43461df91b3SKonstantin Kostiuk 
435b39297aeSTomoki Sekiyama     COMInitializer initializer;
436b39297aeSTomoki Sekiyama     COMPointer<IVssAdmin> pVssAdmin;
437b39297aeSTomoki Sekiyama     HRESULT hr = E_FAIL;
438b39297aeSTomoki Sekiyama     char dllPath[MAX_PATH];
439b39297aeSTomoki Sekiyama     char key[256];
440b39297aeSTomoki Sekiyama 
441b39297aeSTomoki Sekiyama     if (!g_hinstDll) {
442b39297aeSTomoki Sekiyama         errmsg_dialog(hr, "Module instance is not available");
443b39297aeSTomoki Sekiyama         goto out;
444b39297aeSTomoki Sekiyama     }
445b39297aeSTomoki Sekiyama 
44601dc0651SMichael Tokarev     /* Add this module to registry */
447b39297aeSTomoki Sekiyama 
448b39297aeSTomoki Sekiyama     sprintf(key, "CLSID\\%s", g_szClsid);
449b39297aeSTomoki Sekiyama     if (!CreateRegistryKey(key, NULL, g_szClsid)) {
450b39297aeSTomoki Sekiyama         goto out;
451b39297aeSTomoki Sekiyama     }
452b39297aeSTomoki Sekiyama 
453b39297aeSTomoki Sekiyama     if (!GetModuleFileName(g_hinstDll, dllPath, sizeof(dllPath))) {
454b39297aeSTomoki Sekiyama         errmsg_dialog(GetLastError(), "GetModuleFileName failed");
455b39297aeSTomoki Sekiyama         goto out;
456b39297aeSTomoki Sekiyama     }
457b39297aeSTomoki Sekiyama 
458b39297aeSTomoki Sekiyama     sprintf(key, "CLSID\\%s\\InprocServer32", g_szClsid);
459b39297aeSTomoki Sekiyama     if (!CreateRegistryKey(key, NULL, dllPath)) {
460b39297aeSTomoki Sekiyama         goto out;
461b39297aeSTomoki Sekiyama     }
462b39297aeSTomoki Sekiyama 
463b39297aeSTomoki Sekiyama     if (!CreateRegistryKey(key, "ThreadingModel", "Apartment")) {
464b39297aeSTomoki Sekiyama         goto out;
465b39297aeSTomoki Sekiyama     }
466b39297aeSTomoki Sekiyama 
467b39297aeSTomoki Sekiyama     sprintf(key, "CLSID\\%s\\ProgID", g_szClsid);
468b39297aeSTomoki Sekiyama     if (!CreateRegistryKey(key, NULL, g_szProgid)) {
469b39297aeSTomoki Sekiyama         goto out;
470b39297aeSTomoki Sekiyama     }
471b39297aeSTomoki Sekiyama 
472b39297aeSTomoki Sekiyama     if (!CreateRegistryKey(g_szProgid, NULL, QGA_PROVIDER_NAME)) {
473b39297aeSTomoki Sekiyama         goto out;
474b39297aeSTomoki Sekiyama     }
475b39297aeSTomoki Sekiyama 
476b39297aeSTomoki Sekiyama     sprintf(key, "%s\\CLSID", g_szProgid);
477b39297aeSTomoki Sekiyama     if (!CreateRegistryKey(key, NULL, g_szClsid)) {
478b39297aeSTomoki Sekiyama         goto out;
479b39297aeSTomoki Sekiyama     }
480b39297aeSTomoki Sekiyama 
481b39297aeSTomoki Sekiyama     hr = CoCreateInstance(CLSID_VSSCoordinator, NULL, CLSCTX_ALL,
482b39297aeSTomoki Sekiyama                           IID_IVssAdmin, (void **)pVssAdmin.replace());
483b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
484b39297aeSTomoki Sekiyama         errmsg_dialog(hr, "CoCreateInstance(VSSCoordinator) failed");
485b39297aeSTomoki Sekiyama         goto out;
486b39297aeSTomoki Sekiyama     }
487b39297aeSTomoki Sekiyama 
488b39297aeSTomoki Sekiyama     hr = pVssAdmin->RegisterProvider(g_gProviderId, CLSID_QGAVSSProvider,
489b39297aeSTomoki Sekiyama                                      const_cast<WCHAR*>(QGA_PROVIDER_LNAME),
490b39297aeSTomoki Sekiyama                                      VSS_PROV_SOFTWARE,
491b39297aeSTomoki Sekiyama                                      const_cast<WCHAR*>(QGA_PROVIDER_VERSION),
492b39297aeSTomoki Sekiyama                                      g_gProviderVersion);
493b2413df8SSameeh Jubran     if (hr == (long int) VSS_E_PROVIDER_ALREADY_REGISTERED) {
494b2413df8SSameeh Jubran         DllUnregisterServer();
495b2413df8SSameeh Jubran         hr = pVssAdmin->RegisterProvider(g_gProviderId, CLSID_QGAVSSProvider,
496b2413df8SSameeh Jubran                                          const_cast<WCHAR * >
497b2413df8SSameeh Jubran                                          (QGA_PROVIDER_LNAME),
498b2413df8SSameeh Jubran                                          VSS_PROV_SOFTWARE,
499b2413df8SSameeh Jubran                                          const_cast<WCHAR * >
500b2413df8SSameeh Jubran                                          (QGA_PROVIDER_VERSION),
501b2413df8SSameeh Jubran                                          g_gProviderVersion);
502b2413df8SSameeh Jubran     }
503b2413df8SSameeh Jubran 
504b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
505b39297aeSTomoki Sekiyama         errmsg_dialog(hr, "RegisterProvider failed");
506b39297aeSTomoki Sekiyama     }
507b39297aeSTomoki Sekiyama 
508b39297aeSTomoki Sekiyama out:
509b39297aeSTomoki Sekiyama     if (FAILED(hr)) {
510b39297aeSTomoki Sekiyama         DllUnregisterServer();
511b39297aeSTomoki Sekiyama     }
512b39297aeSTomoki Sekiyama 
51361df91b3SKonstantin Kostiuk     qga_debug_end;
514b39297aeSTomoki Sekiyama     return hr;
515b39297aeSTomoki Sekiyama }
516b39297aeSTomoki Sekiyama 
517b39297aeSTomoki Sekiyama /* Unregister this VSS hardware provider from the system */
DllUnregisterServer(void)518b39297aeSTomoki Sekiyama STDAPI DllUnregisterServer(void)
519b39297aeSTomoki Sekiyama {
52061df91b3SKonstantin Kostiuk     qga_debug_begin;
52161df91b3SKonstantin Kostiuk 
522b39297aeSTomoki Sekiyama     TCHAR key[256];
523b39297aeSTomoki Sekiyama     COMInitializer initializer;
524b39297aeSTomoki Sekiyama     COMPointer<IVssAdmin> pVssAdmin;
525b39297aeSTomoki Sekiyama 
526b39297aeSTomoki Sekiyama     HRESULT hr = CoCreateInstance(CLSID_VSSCoordinator,
527b39297aeSTomoki Sekiyama                                   NULL, CLSCTX_ALL, IID_IVssAdmin,
528b39297aeSTomoki Sekiyama                                   (void **)pVssAdmin.replace());
529b39297aeSTomoki Sekiyama     if (SUCCEEDED(hr)) {
530b39297aeSTomoki Sekiyama         hr = pVssAdmin->UnregisterProvider(g_gProviderId);
531b39297aeSTomoki Sekiyama     } else {
532b39297aeSTomoki Sekiyama         errmsg(hr, "CoCreateInstance(VSSCoordinator) failed");
533b39297aeSTomoki Sekiyama     }
534b39297aeSTomoki Sekiyama 
535b39297aeSTomoki Sekiyama     sprintf(key, "CLSID\\%s", g_szClsid);
536b39297aeSTomoki Sekiyama     SHDeleteKey(HKEY_CLASSES_ROOT, key);
537b39297aeSTomoki Sekiyama     SHDeleteKey(HKEY_CLASSES_ROOT, g_szProgid);
538b39297aeSTomoki Sekiyama 
53961df91b3SKonstantin Kostiuk     qga_debug_end;
540b39297aeSTomoki Sekiyama     return S_OK; /* Uninstall should never fail */
541b39297aeSTomoki Sekiyama }
542b39297aeSTomoki Sekiyama 
543b39297aeSTomoki Sekiyama 
544b39297aeSTomoki Sekiyama /* Support function to convert ASCII string into BSTR (used in _bstr_t) */
545b39297aeSTomoki Sekiyama namespace _com_util
546b39297aeSTomoki Sekiyama {
ConvertStringToBSTR(const char * ascii)547b39297aeSTomoki Sekiyama     BSTR WINAPI ConvertStringToBSTR(const char *ascii) {
548b39297aeSTomoki Sekiyama         int len = strlen(ascii);
549b39297aeSTomoki Sekiyama         BSTR bstr = SysAllocStringLen(NULL, len);
550b39297aeSTomoki Sekiyama 
551b39297aeSTomoki Sekiyama         if (!bstr) {
552b39297aeSTomoki Sekiyama             return NULL;
553b39297aeSTomoki Sekiyama         }
554b39297aeSTomoki Sekiyama 
555b39297aeSTomoki Sekiyama         if (mbstowcs(bstr, ascii, len) == (size_t)-1) {
5562f84cf69SKonstantin Kostiuk             qga_debug("Failed to convert string '%s' into BSTR", ascii);
557b39297aeSTomoki Sekiyama             bstr[0] = 0;
558b39297aeSTomoki Sekiyama         }
559b39297aeSTomoki Sekiyama         return bstr;
560b39297aeSTomoki Sekiyama     }
561b39297aeSTomoki Sekiyama }
562f342cc93SSameeh Jubran 
563917ebcb1SBasil Salman /* Stop QGA VSS provider service using Winsvc API  */
StopService(void)564f342cc93SSameeh Jubran STDAPI StopService(void)
565f342cc93SSameeh Jubran {
56661df91b3SKonstantin Kostiuk     qga_debug_begin;
56761df91b3SKonstantin Kostiuk 
5680fcd574bSPierrick Bouvier     HRESULT hr = S_OK;
569917ebcb1SBasil Salman     SC_HANDLE manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
570917ebcb1SBasil Salman     SC_HANDLE service = NULL;
571f342cc93SSameeh Jubran 
572917ebcb1SBasil Salman     if (!manager) {
573917ebcb1SBasil Salman         errmsg(E_FAIL, "Failed to open service manager");
574917ebcb1SBasil Salman         hr = E_FAIL;
575917ebcb1SBasil Salman         goto out;
576917ebcb1SBasil Salman     }
577917ebcb1SBasil Salman     service = OpenService(manager, QGA_PROVIDER_NAME, SC_MANAGER_ALL_ACCESS);
578f342cc93SSameeh Jubran 
579917ebcb1SBasil Salman     if (!service) {
580917ebcb1SBasil Salman         errmsg(E_FAIL, "Failed to open service");
581917ebcb1SBasil Salman         hr =  E_FAIL;
582917ebcb1SBasil Salman         goto out;
583917ebcb1SBasil Salman     }
584917ebcb1SBasil Salman     if (!(ControlService(service, SERVICE_CONTROL_STOP, NULL))) {
585917ebcb1SBasil Salman         errmsg(E_FAIL, "Failed to stop service");
586917ebcb1SBasil Salman         hr = E_FAIL;
587f342cc93SSameeh Jubran     }
588f342cc93SSameeh Jubran 
589f342cc93SSameeh Jubran out:
590917ebcb1SBasil Salman     CloseServiceHandle(service);
591917ebcb1SBasil Salman     CloseServiceHandle(manager);
59261df91b3SKonstantin Kostiuk     qga_debug_end;
593f342cc93SSameeh Jubran     return hr;
594f342cc93SSameeh Jubran }
595