VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxCredProv/VBoxCredProvProvider.cpp@ 62522

Last change on this file since 62522 was 62522, checked in by vboxsync, 8 years ago

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.0 KB
Line 
1/* $Id: VBoxCredProvProvider.cpp 62522 2016-07-22 19:17:25Z vboxsync $ */
2/** @file
3 * VBoxCredProvProvider - The actual credential provider class.
4 */
5
6/*
7 * Copyright (C) 2012-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include <new> /* For bad_alloc. */
23
24#include <credentialprovider.h>
25
26#include <iprt/err.h>
27#include <VBox/VBoxGuestLib.h>
28
29#include "VBoxCredentialProvider.h"
30#include "VBoxCredProvProvider.h"
31#include "VBoxCredProvCredential.h"
32
33
34
35VBoxCredProvProvider::VBoxCredProvProvider(void) :
36 m_cRefs(1),
37 m_pPoller(NULL),
38 m_pCred(NULL),
39 m_pEvents(NULL),
40 m_fHandleRemoteSessions(false)
41{
42 VBoxCredentialProviderAcquire();
43
44 VBoxCredProvReportStatus(VBoxGuestFacilityStatus_Init);
45}
46
47
48VBoxCredProvProvider::~VBoxCredProvProvider(void)
49{
50 VBoxCredProvVerbose(0, "VBoxCredProv: Destroying\n");
51
52 if (m_pCred)
53 {
54 m_pCred->Release();
55 m_pCred = NULL;
56 }
57
58 if (m_pPoller)
59 {
60 m_pPoller->Shutdown();
61 delete m_pPoller;
62 m_pPoller = NULL;
63 }
64
65 VBoxCredProvReportStatus(VBoxGuestFacilityStatus_Terminated);
66
67 VBoxCredentialProviderRelease();
68}
69
70
71/* IUnknown overrides. */
72ULONG
73VBoxCredProvProvider::AddRef(void)
74{
75 LONG cRefs = InterlockedIncrement(&m_cRefs);
76 VBoxCredProvVerbose(0, "VBoxCredProv: AddRef: Returning refcount=%ld\n",
77 cRefs);
78 return cRefs;
79}
80
81
82ULONG
83VBoxCredProvProvider::Release(void)
84{
85 LONG cRefs = InterlockedDecrement(&m_cRefs);
86 VBoxCredProvVerbose(0, "VBoxCredProv: Release: Returning refcount=%ld\n",
87 cRefs);
88 if (!cRefs)
89 {
90 VBoxCredProvVerbose(0, "VBoxCredProv: Calling destructor\n");
91 delete this;
92 }
93 return cRefs;
94}
95
96
97HRESULT
98VBoxCredProvProvider::QueryInterface(REFIID interfaceID, void **ppvInterface)
99{
100 HRESULT hr = S_OK;
101 if (ppvInterface)
102 {
103 if ( IID_IUnknown == interfaceID
104 || IID_ICredentialProvider == interfaceID)
105 {
106 *ppvInterface = static_cast<IUnknown*>(this);
107 reinterpret_cast<IUnknown*>(*ppvInterface)->AddRef();
108 }
109 else
110 {
111 *ppvInterface = NULL;
112 hr = E_NOINTERFACE;
113 }
114 }
115 else
116 hr = E_INVALIDARG;
117
118 return hr;
119}
120
121
122/**
123 * Loads the global configuration from registry.
124 *
125 * @return DWORD Windows error code.
126 */
127DWORD
128VBoxCredProvProvider::LoadConfiguration(void)
129{
130 HKEY hKey;
131 /** @todo Add some registry wrapper function(s) as soon as we got more values to retrieve. */
132 DWORD dwRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Oracle\\VirtualBox Guest Additions\\AutoLogon",
133 0L, KEY_QUERY_VALUE, &hKey);
134 if (dwRet == ERROR_SUCCESS)
135 {
136 DWORD dwValue;
137 DWORD dwType = REG_DWORD;
138 DWORD dwSize = sizeof(DWORD);
139
140 dwRet = RegQueryValueEx(hKey, L"HandleRemoteSessions", NULL, &dwType, (LPBYTE)&dwValue, &dwSize);
141 if ( dwRet == ERROR_SUCCESS
142 && dwType == REG_DWORD
143 && dwSize == sizeof(DWORD))
144 {
145 m_fHandleRemoteSessions = RT_BOOL(dwValue);
146 }
147
148 dwRet = RegQueryValueEx(hKey, L"LoggingEnabled", NULL, &dwType, (LPBYTE)&dwValue, &dwSize);
149 if ( dwRet == ERROR_SUCCESS
150 && dwType == REG_DWORD
151 && dwSize == sizeof(DWORD))
152 {
153 g_dwVerbosity = 1; /* Default logging level. */
154 }
155
156 if (g_dwVerbosity) /* Do we want logging at all? */
157 {
158 dwRet = RegQueryValueEx(hKey, L"LoggingLevel", NULL, &dwType, (LPBYTE)&dwValue, &dwSize);
159 if ( dwRet == ERROR_SUCCESS
160 && dwType == REG_DWORD
161 && dwSize == sizeof(DWORD))
162 {
163 g_dwVerbosity = dwValue;
164 }
165 }
166
167 RegCloseKey(hKey);
168 }
169 /* Do not report back an error here yet. */
170 return ERROR_SUCCESS;
171}
172
173
174/**
175 * Determines whether we should handle the current session or not.
176 *
177 * @return bool true if we should handle this session, false if not.
178 */
179bool
180VBoxCredProvProvider::HandleCurrentSession(void)
181{
182 /* Load global configuration from registry. */
183 int rc = LoadConfiguration();
184 if (RT_FAILURE(rc))
185 VBoxCredProvVerbose(0, "VBoxCredProv: Error loading global configuration, rc=%Rrc\n",
186 rc);
187
188 bool fHandle = false;
189 if (VbglR3AutoLogonIsRemoteSession())
190 {
191 if (m_fHandleRemoteSessions) /* Force remote session handling. */
192 fHandle = true;
193 }
194 else /* No remote session. */
195 fHandle = true;
196
197 VBoxCredProvVerbose(3, "VBoxCredProv: Handling current session=%RTbool\n", fHandle);
198 return fHandle;
199}
200
201
202/**
203 * Tells this provider the current usage scenario.
204 *
205 * @return HRESULT
206 * @param enmUsageScenario Current usage scenario this provider will be
207 * used in.
208 * @param dwFlags Optional flags for the usage scenario.
209 */
210HRESULT
211VBoxCredProvProvider::SetUsageScenario(CREDENTIAL_PROVIDER_USAGE_SCENARIO enmUsageScenario, DWORD dwFlags)
212{
213 HRESULT hr = S_OK;
214 DWORD dwErr;
215
216 VBoxCredProvVerbose(0, "VBoxCredProv::SetUsageScenario: enmUsageScenario=%d, dwFlags=%ld\n",
217 enmUsageScenario, dwFlags);
218
219 m_enmUsageScenario = enmUsageScenario;
220
221 switch (m_enmUsageScenario)
222 {
223 case CPUS_LOGON:
224 case CPUS_UNLOCK_WORKSTATION:
225 {
226 VBoxCredProvReportStatus(VBoxGuestFacilityStatus_Active);
227
228 dwErr = LoadConfiguration();
229 if (dwErr != ERROR_SUCCESS)
230 VBoxCredProvVerbose(0, "VBoxCredProv: Error while loading configuration, error=%ld\n", dwErr);
231 /* Do not stop running on a misconfigured system. */
232
233 /*
234 * If we're told to not handle the current session just bail out and let the
235 * user know.
236 */
237 if (!HandleCurrentSession())
238 break;
239
240 if (!m_pPoller)
241 {
242 try
243 {
244 m_pPoller = new VBoxCredProvPoller();
245 AssertPtr(m_pPoller);
246 int rc = m_pPoller->Initialize(this);
247 if (RT_FAILURE(rc))
248 VBoxCredProvVerbose(0, "VBoxCredProv::SetUsageScenario: Error initializing poller thread, rc=%Rrc\n", rc);
249 }
250 catch (std::bad_alloc &ex)
251 {
252 NOREF(ex);
253 hr = E_OUTOFMEMORY;
254 }
255 }
256
257 if ( SUCCEEDED(hr)
258 && !m_pCred)
259 {
260 try
261 {
262 m_pCred = new VBoxCredProvCredential();
263 AssertPtr(m_pPoller);
264 hr = m_pCred->Initialize(m_enmUsageScenario);
265 }
266 catch (std::bad_alloc &ex)
267 {
268 NOREF(ex);
269 hr = E_OUTOFMEMORY;
270 }
271 }
272 else
273 {
274 /* All set up already! Nothing to do here right now. */
275 }
276
277 /* If we failed, do some cleanup. */
278 if (FAILED(hr))
279 {
280 if (m_pCred != NULL)
281 {
282 m_pCred->Release();
283 m_pCred = NULL;
284 }
285 }
286 break;
287 }
288
289 case CPUS_CHANGE_PASSWORD: /* Asks us to provide a way to change the password. */
290 case CPUS_CREDUI: /* Displays an own UI. We don't need that. */
291 case CPUS_PLAP: /* See Pre-Logon-Access Provider. Not needed (yet). */
292
293 hr = E_NOTIMPL;
294 break;
295
296 default:
297
298 hr = E_INVALIDARG;
299 break;
300 }
301
302 VBoxCredProvVerbose(0, "VBoxCredProv::SetUsageScenario returned hr=0x%08x\n", hr);
303 return hr;
304}
305
306
307/**
308 * Tells this provider how the serialization will be handled. Currently not used.
309 *
310 * @return STDMETHODIMP
311 * @param pcpCredentialSerialization Credentials serialization.
312 */
313STDMETHODIMP
314VBoxCredProvProvider::SetSerialization(const CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION *pcpCredentialSerialization)
315{
316 NOREF(pcpCredentialSerialization);
317 return E_NOTIMPL;
318}
319
320
321/**
322 * Initializes the communication with LogonUI through callbacks events which we can later
323 * use to start re-enumeration of credentials.
324 *
325 * @return HRESULT
326 * @param pcpEvents Pointer to event interface.
327 * @param upAdviseContext The current advise context.
328 */
329HRESULT
330VBoxCredProvProvider::Advise(ICredentialProviderEvents *pcpEvents, UINT_PTR upAdviseContext)
331{
332 VBoxCredProvVerbose(0, "VBoxCredProv::Advise, pcpEvents=0x%p, upAdviseContext=%u\n",
333 pcpEvents, upAdviseContext);
334 if (m_pEvents)
335 {
336 m_pEvents->Release();
337 m_pEvents = NULL;
338 }
339
340 m_pEvents = pcpEvents;
341 if (m_pEvents)
342 m_pEvents->AddRef();
343
344 /*
345 * Save advice context for later use when binding to
346 * certain ICredentialProviderEvents events.
347 */
348 m_upAdviseContext = upAdviseContext;
349 return S_OK;
350}
351
352
353/**
354 * Uninitializes the callback events so that they're no longer valid.
355 *
356 * @return HRESULT
357 */
358HRESULT
359VBoxCredProvProvider::UnAdvise(void)
360{
361 VBoxCredProvVerbose(0, "VBoxCredProv::UnAdvise: pEvents=0x%p\n",
362 m_pEvents);
363 if (m_pEvents)
364 {
365 m_pEvents->Release();
366 m_pEvents = NULL;
367 }
368
369 return S_OK;
370}
371
372
373/**
374 * Retrieves the total count of fields we're handling (needed for field enumeration
375 * through LogonUI).
376 *
377 * @return HRESULT
378 * @param pdwCount Receives total count of fields.
379 */
380HRESULT
381VBoxCredProvProvider::GetFieldDescriptorCount(DWORD *pdwCount)
382{
383 if (pdwCount)
384 {
385 *pdwCount = VBOXCREDPROV_NUM_FIELDS;
386 VBoxCredProvVerbose(0, "VBoxCredProv::GetFieldDescriptorCount: %ld\n", *pdwCount);
387 }
388 return S_OK;
389}
390
391
392/**
393 * Retrieves a descriptor of a specified field.
394 *
395 * @return HRESULT
396 * @param dwIndex ID of field to retrieve descriptor for.
397 * @param ppFieldDescriptor Pointer which receives the allocated field
398 * descriptor.
399 */
400HRESULT
401VBoxCredProvProvider::GetFieldDescriptorAt(DWORD dwIndex, CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR **ppFieldDescriptor)
402{
403 HRESULT hr = S_OK;
404 if ( dwIndex < VBOXCREDPROV_NUM_FIELDS
405 && ppFieldDescriptor)
406 {
407 PCREDENTIAL_PROVIDER_FIELD_DESCRIPTOR pcpFieldDesc =
408 (PCREDENTIAL_PROVIDER_FIELD_DESCRIPTOR)CoTaskMemAlloc(sizeof(CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR));
409
410 if (pcpFieldDesc)
411 {
412 const VBOXCREDPROV_FIELD &field = s_VBoxCredProvFields[dwIndex];
413
414 RT_BZERO(pcpFieldDesc, sizeof(CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR));
415
416 pcpFieldDesc->dwFieldID = field.desc.dwFieldID;
417 pcpFieldDesc->cpft = field.desc.cpft;
418 if (field.desc.pszLabel)
419 hr = SHStrDupW(field.desc.pszLabel, &pcpFieldDesc->pszLabel);
420 }
421 else
422 hr = E_OUTOFMEMORY;
423
424 if (SUCCEEDED(hr))
425 *ppFieldDescriptor = pcpFieldDesc;
426 else
427 CoTaskMemFree(pcpFieldDesc);
428 }
429 else
430 hr = E_INVALIDARG;
431
432 VBoxCredProvVerbose(0, "VBoxCredProv::GetFieldDescriptorAt: dwIndex=%ld, ppDesc=0x%p, hr=0x%08x\n",
433 dwIndex, ppFieldDescriptor, hr);
434 return hr;
435}
436
437
438/**
439 * Retrieves the total number of credentials this provider can offer at the current time and
440 * if a logon attempt should be made.
441 *
442 * @return HRESULT
443 * @param pdwCount Receives number of credentials to serve.
444 * @param pdwDefault Receives the credentials index to try
445 * logging on if there is more than one
446 * credential provided. 0 is default.
447 * @param pfAutoLogonWithDefault Receives a flag indicating whether a
448 * logon attempt using the default
449 * credential should be made or not.
450 */
451HRESULT
452VBoxCredProvProvider::GetCredentialCount(DWORD *pdwCount, DWORD *pdwDefault, BOOL *pfAutoLogonWithDefault)
453{
454 AssertPtr(pdwCount);
455 AssertPtr(pdwDefault);
456 AssertPtr(pfAutoLogonWithDefault);
457
458 bool fHasCredentials = false;
459
460 /* Do we have credentials? */
461 if (m_pCred)
462 {
463 int rc = m_pCred->RetrieveCredentials();
464 fHasCredentials = rc == VINF_SUCCESS;
465 }
466
467 if (fHasCredentials)
468 {
469 *pdwCount = 1; /* This provider always has the same number of credentials (1). */
470 *pdwDefault = 0; /* The credential we provide is *always* at index 0! */
471 *pfAutoLogonWithDefault = TRUE; /* We always at least try to auto-login (if password is correct). */
472 }
473 else
474 {
475 *pdwCount = 0;
476 *pdwDefault = CREDENTIAL_PROVIDER_NO_DEFAULT;
477 *pfAutoLogonWithDefault = FALSE;
478 }
479
480 VBoxCredProvVerbose(0, "VBoxCredProv::GetCredentialCount: *pdwCount=%ld, *pdwDefault=%ld, *pfAutoLogonWithDefault=%s\n",
481 *pdwCount, *pdwDefault, *pfAutoLogonWithDefault ? "true" : "false");
482 return S_OK;
483}
484
485
486/**
487 * Called by Winlogon to retrieve the interface of our current ICredentialProviderCredential interface.
488 *
489 * @return HRESULT
490 * @param dwIndex Index of credential (in case there is more than one credential at a time) to
491 * retrieve the interface for.
492 * @param ppCredProvCredential Pointer that receives the credential interface.
493 */
494HRESULT
495VBoxCredProvProvider::GetCredentialAt(DWORD dwIndex, ICredentialProviderCredential **ppCredProvCredential)
496{
497 VBoxCredProvVerbose(0, "VBoxCredProv::GetCredentialAt: Index=%ld, ppCredProvCredential=0x%p\n",
498 dwIndex, ppCredProvCredential);
499 if (!m_pCred)
500 {
501 VBoxCredProvVerbose(0, "VBoxCredProv::GetCredentialAt: No credentials available\n");
502 return E_INVALIDARG;
503 }
504
505 HRESULT hr;
506 if ( dwIndex == 0
507 && ppCredProvCredential)
508 {
509 hr = m_pCred->QueryInterface(IID_ICredentialProviderCredential,
510 reinterpret_cast<void**>(ppCredProvCredential));
511 }
512 else
513 {
514 VBoxCredProvVerbose(0, "VBoxCredProv::GetCredentialAt: More than one credential not supported!\n");
515 hr = E_INVALIDARG;
516 }
517 return hr;
518}
519
520
521/**
522 * Triggers a credential re-enumeration -- will be called by our poller thread. This then invokes
523 * GetCredentialCount() and GetCredentialAt() called by Winlogon.
524 */
525void
526VBoxCredProvProvider::OnCredentialsProvided(void)
527{
528 VBoxCredProvVerbose(0, "VBoxCredProv::OnCredentialsProvided\n");
529
530 if (m_pEvents)
531 m_pEvents->CredentialsChanged(m_upAdviseContext);
532}
533
534
535/**
536 * Creates our provider. This happens *before* CTRL-ALT-DEL was pressed!
537 */
538HRESULT
539VBoxCredProvProviderCreate(REFIID interfaceID, void **ppvInterface)
540{
541 HRESULT hr;
542
543 try
544 {
545 VBoxCredProvProvider *pProvider = new VBoxCredProvProvider();
546 AssertPtr(pProvider);
547 hr = pProvider->QueryInterface(interfaceID, ppvInterface);
548 pProvider->Release();
549 }
550 catch (std::bad_alloc &ex)
551 {
552 NOREF(ex);
553 hr = E_OUTOFMEMORY;
554 }
555
556 return hr;
557}
558
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette