VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxCredProv/VBoxCredentialProvider.cpp

Last change on this file was 99828, checked in by vboxsync, 12 months ago

*: A bunch of adjustments that allows using /permissive- with Visual C++ (qt 6.x necessity).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.4 KB
Line 
1/* $Id: VBoxCredentialProvider.cpp 99828 2023-05-17 13:48:57Z vboxsync $ */
2/** @file
3 * VBoxCredentialProvider - Main file of the VirtualBox Credential Provider.
4 */
5
6/*
7 * Copyright (C) 2012-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include <iprt/win/windows.h>
33#include <initguid.h>
34#include <new> /* For bad_alloc. */
35
36#ifdef VBOX_WITH_WIN_SENS
37# include <eventsys.h>
38# include <sens.h>
39# include <Sensevts.h>
40#endif
41
42#include <iprt/buildconfig.h>
43#include <iprt/initterm.h>
44#ifdef VBOX_WITH_WIN_SENS
45# include <VBox/com/string.h>
46using namespace com;
47#endif
48#include <VBox/VBoxGuestLib.h>
49
50#include "VBoxCredentialProvider.h"
51#include "VBoxCredProvFactory.h"
52
53
54/*********************************************************************************************************************************
55* Global Variables *
56*********************************************************************************************************************************/
57static LONG g_cDllRefs = 0; /**< Global DLL reference count. */
58static HINSTANCE g_hDllInst = NULL; /**< Global DLL hInstance. */
59
60#ifdef VBOX_WITH_WIN_SENS
61
62static bool g_fSENSEnabled = false;
63static IEventSystem *g_pIEventSystem = NULL; /**< Pointer to IEventSystem interface. */
64
65/**
66 * Subscribed SENS events.
67 */
68static struct VBOXCREDPROVSENSEVENTS
69{
70 /** The actual method name the subscription is for. */
71 const char *pszMethod;
72 /** A friendly name for the subscription. */
73 const char *pszSubscriptionName;
74 /** The actual subscription UUID.
75 * Should not be changed. */
76 const char *pszSubscriptionUUID;
77} g_aSENSEvents[] = {
78 { "Logon", "VBoxCredProv SENS Logon", "{561D0791-47C0-4BC3-87C0-CDC2621EA653}" },
79 { "Logoff", "VBoxCredProv SENS Logoff", "{12B618B1-F2E0-4390-BADA-7EB1DC31A70A}" },
80 { "StartShell", "VBoxCredProv SENS StartShell", "{5941931D-015A-4F91-98DA-81AAE262D090}" },
81 { "DisplayLock", "VBoxCredProv SENS DisplayLock", "{B7E2C510-501A-4961-938F-A458970930D7}" },
82 { "DisplayUnlock", "VBoxCredProv SENS DisplayUnlock", "{11305987-8FFC-41AD-A264-991BD5B7488A}" },
83 { "StartScreenSaver", "VBoxCredProv SENS StartScreenSaver", "{6E2D26DF-0095-4EC4-AE00-2395F09AF7F2}" },
84 { "StopScreenSaver", "VBoxCredProv SENS StopScreenSaver", "{F53426BC-412F-41E8-9A5F-E5FA8A164BD6}" }
85};
86
87/**
88 * Implementation of the ISensLogon interface for getting
89 * SENS (System Event Notification Service) events. SENS must be up
90 * and running on this OS!
91 */
92interface VBoxCredProvSensLogon : public ISensLogon
93{
94public:
95
96 VBoxCredProvSensLogon(void)
97 : m_cRefs(1)
98 {
99 }
100
101 virtual ~VBoxCredProvSensLogon()
102 {
103 /* Make VC++ 19.2 happy. */
104 }
105
106 STDMETHODIMP QueryInterface(REFIID interfaceID, void **ppvInterface)
107 {
108 if ( IsEqualIID(interfaceID, IID_IUnknown)
109 || IsEqualIID(interfaceID, IID_IDispatch)
110 || IsEqualIID(interfaceID, IID_ISensLogon))
111 {
112 *ppvInterface = this;
113 AddRef();
114 return S_OK;
115 }
116
117 *ppvInterface = NULL;
118 return E_NOINTERFACE;
119 }
120
121 ULONG STDMETHODCALLTYPE AddRef(void)
122 {
123 return InterlockedIncrement(&m_cRefs);
124 }
125
126 ULONG STDMETHODCALLTYPE Release(void)
127 {
128 ULONG ulTemp = InterlockedDecrement(&m_cRefs);
129 return ulTemp;
130 }
131
132 HRESULT STDMETHODCALLTYPE GetTypeInfoCount(unsigned int FAR *pctInfo)
133 {
134 RT_NOREF(pctInfo);
135 return E_NOTIMPL;
136 }
137
138 HRESULT STDMETHODCALLTYPE GetTypeInfo(unsigned int iTInfo, LCID lcid, ITypeInfo FAR * FAR *ppTInfo)
139 {
140 RT_NOREF(iTInfo, lcid, ppTInfo);
141 return E_NOTIMPL;
142 }
143
144 HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, OLECHAR FAR * FAR *rgszNames, unsigned int cNames,
145 LCID lcid, DISPID FAR *rgDispId)
146 {
147 RT_NOREF(riid, rgszNames, cNames, lcid, rgDispId);
148 return E_NOTIMPL;
149 }
150
151 HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pDispParams,
152 VARIANT FAR *parResult, EXCEPINFO FAR *pExcepInfo, unsigned int FAR *puArgErr)
153 {
154 RT_NOREF(dispIdMember, riid, lcid, wFlags, pDispParams, parResult, pExcepInfo, puArgErr);
155 return E_NOTIMPL;
156 }
157
158 /* ISensLogon methods */
159 STDMETHODIMP Logon(BSTR bstrUserName)
160 {
161 RT_NOREF(bstrUserName);
162 VBoxCredProvVerbose(0, "VBoxCredProvSensLogon: Logon\n");
163 return S_OK;
164 }
165
166 STDMETHODIMP Logoff(BSTR bstrUserName)
167 {
168 RT_NOREF(bstrUserName);
169 VBoxCredProvVerbose(0, "VBoxCredProvSensLogon: Logoff\n");
170 return S_OK;
171 }
172
173 STDMETHODIMP StartShell(BSTR bstrUserName)
174 {
175 RT_NOREF(bstrUserName);
176 VBoxCredProvVerbose(0, "VBoxCredProvSensLogon: Logon\n");
177 return S_OK;
178 }
179
180 STDMETHODIMP DisplayLock(BSTR bstrUserName)
181 {
182 RT_NOREF(bstrUserName);
183 VBoxCredProvVerbose(0, "VBoxCredProvSensLogon: DisplayLock\n");
184 return S_OK;
185 }
186
187 STDMETHODIMP DisplayUnlock(BSTR bstrUserName)
188 {
189 RT_NOREF(bstrUserName);
190 VBoxCredProvVerbose(0, "VBoxCredProvSensLogon: DisplayUnlock\n");
191 return S_OK;
192 }
193
194 STDMETHODIMP StartScreenSaver(BSTR bstrUserName)
195 {
196 RT_NOREF(bstrUserName);
197 VBoxCredProvVerbose(0, "VBoxCredProvSensLogon: StartScreenSaver\n");
198 return S_OK;
199 }
200
201 STDMETHODIMP StopScreenSaver(BSTR bstrUserName)
202 {
203 RT_NOREF(bstrUserName);
204 VBoxCredProvVerbose(0, "VBoxCredProvSensLogon: StopScreenSaver\n");
205 return S_OK;
206 }
207
208protected:
209
210 LONG m_cRefs;
211};
212static VBoxCredProvSensLogon *g_pISensLogon = NULL;
213
214
215/**
216 * Register events to be called by SENS.
217 *
218 * @return HRESULT
219 */
220static HRESULT VBoxCredentialProviderRegisterSENS(void)
221{
222 VBoxCredProvVerbose(0, "VBoxCredentialProviderRegisterSENS\n");
223
224 HRESULT hr = CoCreateInstance(CLSID_CEventSystem, 0, CLSCTX_SERVER, IID_IEventSystem, (void**)&g_pIEventSystem);
225 if (FAILED(hr))
226 {
227 VBoxCredProvVerbose(0, "VBoxCredentialProviderRegisterSENS: Could not connect to CEventSystem, hr=%Rhrc\n", hr);
228 return hr;
229 }
230
231#ifdef RT_EXCEPTIONS_ENABLED
232 try { g_pISensLogon = new VBoxCredProvSensLogon(); }
233 catch (std::bad_alloc &) { AssertFailedReturn(E_OUTOFMEMORY); }
234#else
235 g_pISensLogon = new VBoxCredProvSensLogon();
236 AssertReturn(g_pISensLogon, E_OUTOFMEMORY);
237#endif
238
239 AssertPtr(g_pIEventSystem);
240 AssertPtr(g_pISensLogon);
241
242 IEventSubscription *pIEventSubscription = NULL;
243 int i;
244 for (i = 0; i < RT_ELEMENTS(g_aSENSEvents); i++)
245 {
246 VBoxCredProvVerbose(0, "VBoxCredProv: Registering \"%s\" (%s) ...\n",
247 g_aSENSEvents[i].pszMethod, g_aSENSEvents[i].pszSubscriptionName);
248
249 hr = CoCreateInstance(CLSID_CEventSubscription, 0, CLSCTX_SERVER, IID_IEventSubscription, (LPVOID*)&pIEventSubscription);
250 if (FAILED(hr))
251 continue;
252
253 Bstr bstrTmp;
254 hr = bstrTmp.assignEx("{d5978630-5b9f-11d1-8dd2-00aa004abd5e}" /* SENSGUID_EVENTCLASS_LOGON */);
255 AssertBreak(SUCCEEDED(hr));
256 hr = pIEventSubscription->put_EventClassID(bstrTmp.raw());
257 if (FAILED(hr))
258 break;
259
260 hr = pIEventSubscription->put_SubscriberInterface((IUnknown *)g_pISensLogon);
261 if (FAILED(hr))
262 break;
263
264 hr = bstrTmp.assignEx(g_aSENSEvents[i].pszMethod);
265 AssertBreak(SUCCEEDED(hr));
266 hr = pIEventSubscription->put_MethodName(bstrTmp.raw());
267 if (FAILED(hr))
268 break;
269
270 hr = bstrTmp.assignEx(g_aSENSEvents[i].pszSubscriptionName);
271 AssertBreak(SUCCEEDED(hr));
272 hr = pIEventSubscription->put_SubscriptionName(bstrTmp.raw());
273 if (FAILED(hr))
274 break;
275
276 hr = bstrTmp.assignEx(g_aSENSEvents[i].pszSubscriptionUUID);
277 AssertBreak(SUCCEEDED(hr));
278 hr = pIEventSubscription->put_SubscriptionID(bstrTmp.raw());
279 if (FAILED(hr))
280 break;
281
282 hr = pIEventSubscription->put_PerUser(TRUE);
283 if (FAILED(hr))
284 break;
285
286 hr = g_pIEventSystem->Store((BSTR)PROGID_EventSubscription, (IUnknown*)pIEventSubscription);
287 if (FAILED(hr))
288 break;
289
290 pIEventSubscription->Release();
291 pIEventSubscription = NULL;
292 }
293
294 if (FAILED(hr))
295 VBoxCredProvVerbose(0, "VBoxCredentialProviderRegisterSENS: Could not register \"%s\" (%s), hr=%Rhrc\n",
296 g_aSENSEvents[i].pszMethod, g_aSENSEvents[i].pszSubscriptionName, hr);
297
298 if (pIEventSubscription != NULL)
299 pIEventSubscription->Release();
300
301 if (FAILED(hr))
302 {
303 VBoxCredProvVerbose(0, "VBoxCredentialProviderRegisterSENS: Error registering SENS provider, hr=%Rhrc\n", hr);
304
305 if (g_pISensLogon)
306 {
307 delete g_pISensLogon;
308 g_pISensLogon = NULL;
309 }
310
311 if (g_pIEventSystem)
312 {
313 g_pIEventSystem->Release();
314 g_pIEventSystem = NULL;
315 }
316 }
317
318 VBoxCredProvVerbose(0, "VBoxCredentialProviderRegisterSENS: Returning hr=%Rhrc\n", hr);
319 return hr;
320}
321
322/**
323 * Unregisters registered SENS events.
324 */
325static void VBoxCredentialProviderUnregisterSENS(void)
326{
327 if (g_pIEventSystem)
328 {
329 g_pIEventSystem->Release();
330 g_pIEventSystem = NULL;
331 }
332
333 /* We need to reconnecto to the event system because we can be called
334 * in a different context COM can't handle. */
335 HRESULT hr = CoCreateInstance(CLSID_CEventSystem, 0,
336 CLSCTX_SERVER, IID_IEventSystem, (void**)&g_pIEventSystem);
337 if (FAILED(hr))
338 VBoxCredProvVerbose(0, "VBoxCredentialProviderUnregisterSENS: Could not reconnect to CEventSystem, hr=%Rhrc\n", hr);
339
340 VBoxCredProvVerbose(0, "VBoxCredentialProviderUnregisterSENS\n");
341
342 for (int i = 0; i < RT_ELEMENTS(g_aSENSEvents); i++)
343 {
344 Bstr bstrSubToRemove;
345 hr = bstrSubToRemove.printfNoThrow("SubscriptionID=%s", g_aSENSEvents[i].pszSubscriptionUUID);
346 AssertContinue(SUCCEEDED(hr)); /* keep going */
347 int iErrorIdX;
348 hr = g_pIEventSystem->Remove((BSTR)PROGID_EventSubscription, bstrSubToRemove.raw(), &iErrorIdX);
349 if (FAILED(hr))
350 {
351 VBoxCredProvVerbose(0, "VBoxCredentialProviderUnregisterSENS: Could not unregister \"%s\" (query: %ls), hr=%Rhrc (index: %d)\n",
352 g_aSENSEvents[i].pszMethod, bstrSubToRemove.raw(), hr, iErrorIdX);
353 /* Keep going. */
354 }
355 }
356
357 if (g_pISensLogon)
358 {
359 delete g_pISensLogon;
360 g_pISensLogon = NULL;
361 }
362
363 if (g_pIEventSystem)
364 {
365 g_pIEventSystem->Release();
366 g_pIEventSystem = NULL;
367 }
368
369 VBoxCredProvVerbose(0, "VBoxCredentialProviderUnregisterSENS: Returning hr=%Rhrc\n", hr);
370}
371
372#endif /* VBOX_WITH_WIN_SENS */
373
374BOOL WINAPI DllMain(HINSTANCE hInst, DWORD dwReason, LPVOID pReserved)
375{
376 NOREF(pReserved);
377
378 g_hDllInst = hInst;
379
380 switch (dwReason)
381 {
382 case DLL_PROCESS_ATTACH:
383 {
384 int rc = RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE);
385 if (RT_SUCCESS(rc))
386 rc = VbglR3Init();
387
388 if (RT_SUCCESS(rc))
389 {
390 VBoxCredProvVerbose(0, "VBoxCredProv: v%s r%s (%s %s) loaded (refs=%ld)\n",
391 RTBldCfgVersion(), RTBldCfgRevisionStr(),
392 __DATE__, __TIME__, g_cDllRefs);
393 }
394
395 DisableThreadLibraryCalls(hInst);
396 break;
397 }
398
399 case DLL_PROCESS_DETACH:
400
401 VBoxCredProvVerbose(0, "VBoxCredProv: Unloaded (refs=%ld)\n", g_cDllRefs);
402 if (!g_cDllRefs)
403 VbglR3Term();
404 break;
405
406 case DLL_THREAD_ATTACH:
407 case DLL_THREAD_DETACH:
408 break;
409
410 default:
411 break;
412 }
413
414 return TRUE;
415}
416
417
418/**
419 * Increments the reference count by one. Must be released
420 * with VBoxCredentialProviderRelease() when finished.
421 */
422void VBoxCredentialProviderAcquire(void)
423{
424 LONG cRefCount = InterlockedIncrement(&g_cDllRefs);
425 VBoxCredProvVerbose(0, "VBoxCredentialProviderAcquire: Increasing global refcount to %ld\n",
426 cRefCount);
427}
428
429
430/**
431 * Decrements the reference count by one.
432 */
433void VBoxCredentialProviderRelease(void)
434{
435 LONG cRefCount = InterlockedDecrement(&g_cDllRefs);
436 VBoxCredProvVerbose(0, "VBoxCredentialProviderRelease: Decreasing global refcount to %ld\n",
437 cRefCount);
438}
439
440
441/**
442 * Returns the current DLL reference count.
443 *
444 * @return LONG The current reference count.
445 */
446LONG VBoxCredentialProviderRefCount(void)
447{
448 return g_cDllRefs;
449}
450
451
452/**
453 * Entry point for determining whether the credential
454 * provider DLL can be unloaded or not.
455 *
456 * @return HRESULT
457 */
458HRESULT __stdcall DllCanUnloadNow(void)
459{
460 VBoxCredProvVerbose(0, "DllCanUnloadNow (refs=%ld)\n",
461 g_cDllRefs);
462
463#ifdef VBOX_WITH_WIN_SENS
464 if (!g_cDllRefs)
465 {
466 if (g_fSENSEnabled)
467 VBoxCredentialProviderUnregisterSENS();
468
469 CoUninitialize();
470 }
471#endif
472 return (g_cDllRefs > 0) ? S_FALSE : S_OK;
473}
474
475
476/**
477 * Create the VirtualBox credential provider by creating
478 * its factory which then in turn can create instances of the
479 * provider itself.
480 *
481 * @return HRESULT
482 * @param classID The class ID.
483 * @param interfaceID The interface ID.
484 * @param ppvInterface Receives the interface pointer on successful
485 * object creation.
486 */
487HRESULT VBoxCredentialProviderCreate(REFCLSID classID, REFIID interfaceID, void **ppvInterface)
488{
489 HRESULT hr;
490 if (classID == CLSID_VBoxCredProvider)
491 {
492 {
493 VBoxCredProvFactory *pFactory;
494#ifdef RT_EXCEPTIONS_ENABLED
495 try { pFactory = new VBoxCredProvFactory(); }
496 catch (std::bad_alloc &) { AssertFailedReturn(E_OUTOFMEMORY); }
497#else
498 pFactory = new VBoxCredProvFactory();
499 AssertReturn(pFactory, E_OUTOFMEMORY);
500#endif
501
502 hr = pFactory->QueryInterface(interfaceID, ppvInterface);
503 pFactory->Release(); /* pFactor is no longer valid (QueryInterface might've failed) */
504 }
505
506#ifdef VBOX_WITH_WIN_SENS
507 g_fSENSEnabled = true; /* By default SENS support is enabled. */
508
509 HKEY hKey;
510 /** @todo Add some registry wrapper function(s) as soon as we got more values to retrieve. */
511 DWORD dwRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Oracle\\VirtualBox Guest Additions\\AutoLogon",
512 0L, KEY_QUERY_VALUE, &hKey);
513 if (dwRet == ERROR_SUCCESS)
514 {
515 DWORD dwValue;
516 DWORD dwType = REG_DWORD;
517 DWORD dwSize = sizeof(DWORD);
518 dwRet = RegQueryValueExW(hKey, L"HandleSENS", NULL, &dwType, (LPBYTE)&dwValue, &dwSize);
519 if ( dwRet == ERROR_SUCCESS
520 && dwType == REG_DWORD
521 && dwSize == sizeof(DWORD))
522 {
523 g_fSENSEnabled = RT_BOOL(dwValue);
524 }
525
526 RegCloseKey(hKey);
527 }
528
529 VBoxCredProvVerbose(0, "VBoxCredentialProviderCreate: g_fSENSEnabled=%RTbool\n", g_fSENSEnabled);
530 if ( SUCCEEDED(hr)
531 && g_fSENSEnabled)
532 {
533 HRESULT hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
534 RT_NOREF(hRes); /* probably a great idea to ignore this */
535 VBoxCredentialProviderRegisterSENS();
536 }
537#else /* !VBOX_WITH_WIN_SENS */
538 VBoxCredProvVerbose(0, "VBoxCredentialProviderCreate: SENS support is disabled\n");
539#endif /* !VBOX_WITH_WIN_SENS */
540 }
541 else
542 hr = CLASS_E_CLASSNOTAVAILABLE;
543
544 return hr;
545}
546
547
548/**
549 * Entry point for getting the actual credential provider
550 * class object.
551 *
552 * @return HRESULT
553 * @param classID The class ID.
554 * @param interfaceID The interface ID.
555 * @param ppvInterface Receives the interface pointer on successful
556 * object creation.
557 */
558HRESULT __stdcall DllGetClassObject(REFCLSID classID, REFIID interfaceID, void **ppvInterface)
559{
560 VBoxCredProvVerbose(0, "DllGetClassObject (refs=%ld)\n",
561 g_cDllRefs);
562
563 return VBoxCredentialProviderCreate(classID, interfaceID, ppvInterface);
564}
565
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use