VBoxCredProvProvider.cpp revision 04c077e3c2bfacb8a42b4ee801ca025e94a9f0eb
/* $Id$ */
/** @file
* VBoxCredProvProvider - The actual credential provider class.
*/
/*
* Copyright (C) 2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#include <credentialprovider.h>
#include <VBox/VBoxGuestLib.h>
#include "VBoxCredentialProvider.h"
#include "VBoxCredProvProvider.h"
#include "VBoxCredProvCredential.h"
VBoxCredProvProvider::VBoxCredProvProvider(void) :
m_cRefCount(1),
m_fHandleRemoteSessions(false)
{
}
{
VBoxCredProvVerbose(0, "VBoxCredProv: Destroying\n");
if (m_pCred)
{
}
if (m_pPoller)
{
delete m_pPoller;
}
}
/* IUnknown overrides. */
{
VBoxCredProvVerbose(0, "VBoxCredProv: AddRef: Returning refcount=%ld\n",
return cRefCount;
}
{
VBoxCredProvVerbose(0, "VBoxCredProv: Release: Returning refcount=%ld\n",
if (!cRefCount)
{
VBoxCredProvVerbose(0, "VBoxCredProv: Calling destructor\n");
delete this;
}
return cRefCount;
}
{
if (ppvInterface)
{
if ( IID_IUnknown == interfaceID
{
*ppvInterface = static_cast<IUnknown*>(this);
}
else
{
*ppvInterface = NULL;
hr = E_NOINTERFACE;
}
}
else
hr = E_INVALIDARG;
return hr;
}
/**
* Loads the global configuration from registry.
*
* @return DWORD Windows error code.
*/
{
/** @todo Add some registry wrapper function(s) as soon as we got more values to retrieve. */
DWORD dwRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Oracle\\VirtualBox Guest Additions\\AutoLogon",
0L, KEY_QUERY_VALUE, &hKey);
if (dwRet == ERROR_SUCCESS)
{
if ( dwRet == ERROR_SUCCESS
{
m_fHandleRemoteSessions = true;
}
if ( dwRet == ERROR_SUCCESS
{
}
if (g_dwVerbosity) /* Do we want logging at all? */
{
if ( dwRet == ERROR_SUCCESS
{
}
}
}
/* Do not report back an error here yet. */
return ERROR_SUCCESS;
}
/**
* Determines whether we should handle the current session or not.
*
* @return bool true if we should handle this session, false if not.
*/
bool VBoxCredProvProvider::HandleCurrentSession(void)
{
/* Load global configuration from registry. */
int rc = LoadConfiguration();
if (RT_FAILURE(rc))
VBoxCredProvVerbose(0, "VBoxCredProv: Error loading global configuration, rc=%Rrc\n",
rc);
bool fHandle = false;
{
if (m_fHandleRemoteSessions) /* Force remote session handling. */
fHandle = true;
}
else /* No remote session. */
fHandle = true;
return fHandle;
}
/*
* SetUsageScenario is the provider's cue that it's going to be asked for tiles
* in a subsequent call. This call happens after the user pressed CTRL+ALT+DEL
* and we need to handle the CPUS_LOGON event.
*/
{
VBoxCredProvVerbose(0, "VBoxCredProv::SetUsageScenario: cpUS=%d, dwFlags=%ld\n",
/* Decide which scenarios to support here. Returning E_NOTIMPL simply tells the caller
* that we're not designed for that scenario. */
switch (m_cpUsageScenario)
{
case CPUS_LOGON:
case CPUS_UNLOCK_WORKSTATION:
dwErr = LoadConfiguration();
if (dwErr != ERROR_SUCCESS)
/* Do not stop running on a misconfigured system. */
/*
* If we're told to not handle the current session just bail out and let the
* user know.
*/
if (!HandleCurrentSession())
break;
if (!m_pPoller)
{
m_pPoller = new VBoxCredProvPoller();
if (RT_FAILURE(rc))
VBoxCredProvVerbose(0, "VBoxCredProv::SetUsageScenario: Error initializing poller thread, rc=%Rrc\n", rc);
}
if (!m_pCred)
{
m_pCred = new VBoxCredProvCredential();
if (m_pCred)
{
}
else
hr = E_OUTOFMEMORY;
}
else
{
/* All set up already! Nothing to do here right now. */
}
/* If we failed, do some cleanup. */
{
{
}
}
break;
case CPUS_CHANGE_PASSWORD:
case CPUS_CREDUI:
case CPUS_PLAP:
break;
default:
hr = E_INVALIDARG;
break;
}
return hr;
}
/*
* SetSerialization takes the kind of buffer that you would normally return to LogonUI for
* an authentication attempt. It's the opposite of ICredentialProviderCredential::GetSerialization.
* GetSerialization is implement by a credential and serializes that credential. Instead,
* SetSerialization takes the serialization and uses it to create a credential.
*
* SetSerialization is called for two main scenarios. The first scenario is in the credUI case
* where it is prepopulating a tile with credentials that the user chose to store in the OS.
* The second situation is in a remote logon case where the remote client may wish to
* prepopulate a tile with a username, or in some cases, completely populate the tile and
* use it to logon without showing any UI.
*/
STDMETHODIMP VBoxCredProvProvider::SetSerialization(const CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION *pcpCredentialSerialization)
{
return E_NOTIMPL;
}
/*
* Called by LogonUI to give you a callback. Providers often use the callback if they
* some event would cause them to need to change the set of tiles (visible UI elements)
* that they enumerated.
*/
{
VBoxCredProvVerbose(0, "VBoxCredProv::Advise, pcpEvents=0x%p, upAdviseContext=%u\n",
if (m_pEvents)
{
}
if (m_pEvents)
/*
* Save advice context for later use when binding to
* certain ICredentialProviderEvents events.
*/
return S_OK;
}
/* Called by LogonUI when the ICredentialProviderEvents callback is no longer valid. */
{
VBoxCredProvVerbose(0, "VBoxCredProv::UnAdvise: pEvents=0x%p\n",
if (m_pEvents)
{
}
return S_OK;
}
/*
* Called by LogonUI to determine the number of fields in your tiles. This
* does mean that all your tiles must have the same number of fields.
* This number must include both visible and invisible fields. If you want a tile
* to have different fields from the other tiles you enumerate for a given usage
* using the field descriptors.
*/
{
if (pdwCount)
{
}
return S_OK;
}
/* Returns the field descriptor for a particular field. */
{
/* Verify dwIndex is a valid field. */
if ( dwIndex < VBOXCREDPROV_NUM_FIELDS
{
(PCREDENTIAL_PROVIDER_FIELD_DESCRIPTOR)CoTaskMemAlloc(sizeof(CREDENTIAL_PROVIDER_FIELD_DESCRIPTOR));
if (pcpFieldDesc)
{
}
else
hr = E_OUTOFMEMORY;
{
}
else
}
else
hr = E_INVALIDARG;
VBoxCredProvVerbose(0, "VBoxCredProv::GetFieldDescriptorAt: dwIndex=%ld, ppDesc=0x%p, hr=0x%08x\n",
return hr;
}
/*
* Sets pdwCount to the number of tiles that we wish to show at this time.
* Sets pdwDefault to the index of the tile which should be used as the default.
*
* The default tile is the tile which will be shown in the zoomed view by default. If
* more than one provider specifies a default tile the behavior is the last used cred
* prov gets to specify the default tile to be displayed
*
* If *pbAutoLogonWithDefault is TRUE, LogonUI will immediately call GetSerialization
* on the credential you've specified as the default and will submit that credential
* for authentication without showing any further UI.
*/
{
bool fHasCredentials = false;
/* Do we have credentials? */
if (m_pCred)
{
}
if (fHasCredentials)
{
*pdwDefault = 0; /* The credential we provide is *always* at index 0! */
*pbAutoLogonWithDefault = TRUE; /* We always at least try to auto-login (if password is correct). */
}
else
{
*pdwCount = 0;
}
VBoxCredProvVerbose(0, "VBoxCredProv::GetCredentialCount: *pdwCount=%ld, *pdwDefault=%ld, *pbAutoLogonWithDefault=%s\n",
return S_OK;
}
/*
* Returns the credential at the index specified by dwIndex. This function is called by logonUI to enumerate
* the tiles.
*/
{
VBoxCredProvVerbose(0, "VBoxCredProv::GetCredentialAt: Index=%ld, ppCredProvCredential=0x%p\n",
if (!m_pCred)
{
VBoxCredProvVerbose(0, "VBoxCredProv::GetCredentialAt: No credentials available\n");
return E_INVALIDARG;
}
/* Validate parameters (we only have one credential). */
if( dwIndex == 0
{
reinterpret_cast<void**>(ppCredProvCredential));
}
else
{
VBoxCredProvVerbose(0, "VBoxCredProv::GetCredentialAt: More than one credential not supported!\n");
hr = E_INVALIDARG;
}
return hr;
}
/* Do a credential re-enumeration if we got the event to do so. This then invokes
* GetCredentialCount() and GetCredentialAt() called by Winlogon. */
void VBoxCredProvProvider::OnCredentialsProvided(void)
{
VBoxCredProvVerbose(0, "VBoxCredProv::OnCredentialsProvided\n");
if (m_pEvents)
}
/* Creates our provider. This happens *before* CTRL-ALT-DEL was pressed! */
{
if (pProvider)
{
}
else
hr = E_OUTOFMEMORY;
return hr;
}