VBoxCredential.cpp revision dee9dd86962066a952b5343dc01f59328f532138
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// PARTICULAR PURPOSE.
//
// Copyright (c) 2006 Microsoft Corporation. All rights reserved.
//
// Modifications (c) 2009-2010 Oracle Corporation
//
#ifndef WIN32_NO_STATUS
#include <ntstatus.h>
#define WIN32_NO_STATUS
#endif
#include "VBoxCredProv.h"
#include "VBoxCredential.h"
#include "guid.h"
#include <lm.h>
struct REPORT_RESULT_STATUS_INFO
{
};
static const REPORT_RESULT_STATUS_INFO s_rgLogonStatusInfo[] =
{
};
{
Log(("VBoxCredential::VBoxCredential\n"));
DllAddRef();
}
{
Log(("VBoxCredential::~VBoxCredential\n"));
Reset();
for (int i = 0; i < ARRAYSIZE(m_rgFieldStrings); i++)
{
}
DllRelease();
}
{
if (pwszString)
}
void VBoxCredential::Reset(void)
{
{
}
}
const char *pszPw,
const char *pszDomain)
{
Log(("VBoxCredential::Update: User=%s, Password=%s, Domain=%s\n",
/* Update user name. */
{
/*
* In case we got a "display name" (e.g. "John Doe")
* instead of the real user name (e.g. "jdoe") we have
* to translate the data first ...
*/
{
}
}
/* Update password. */
{
}
/*
* Update domain name (can be NULL) and will
* be later replaced by the local computer name in the
* Kerberos authentication package.
*/
{
}
Log(("VBoxCredential::Update: Finished - User=%ls, Password=%ls, Domain=%ls\n",
return S_OK;
}
/*
* Initializes one credential with the field information passed in.
* Set the value of the SFI_USERNAME field to pwzUsername.
* Optionally takes a password for the SetSerialization case.
*/
const FIELD_STATE_PAIR* rgfsp)
{
/*
* Copy the field descriptors for each field. This is useful if you want to vary the
* field descriptors based on what Usage scenario the credential was created for.
*/
{
m_rgFieldStatePairs[i] = rgfsp[i];
}
/* Fill in the default value to make winlogon happy. */
return S_OK;
}
/*
* LogonUI calls this in order to give us a callback in case we need to notify it of anything.
* Store this callback pointer for later use.
*/
{
Log(("VBoxCredential::Advise\n"));
if (m_pCredProvCredentialEvents != NULL)
return S_OK;
}
/* LogonUI calls this to tell us to release the callback. */
{
Log(("VBoxCredential::UnAdvise\n"));
/*
* We're done with the current iteration, trigger a refresh of ourselves
* to reset credentials and to keep the logon UI clean (no stale entries anymore).
*/
Reset();
/*
* Force a re-iteration of the provider (which will give zero credentials
* to try out because we just resetted our one and only a line above.
*/
if (m_pProvider)
return S_OK;
}
/*
* LogonUI calls this function when our tile is selected (zoomed).
* there's no need to do anything here - you can set that up in the
* field definitions. But if you want to do something
* more complicated, like change the contents of a field when the tile is
* selected, you would do it here.
*/
{
Log(("VBoxCredential::SetSelected\n"));
/*
* Don't do auto logon here because it would retry too often with
* every credential field (user name, password, domain, ...) which makes
* winlogon wait before new login attempts can be made.
*/
*pbAutoLogon = FALSE;
return S_OK;
}
/*
* Similarly to SetSelected, LogonUI calls this when your tile was selected
* and now no longer is. The most common thing to do here (which we do below)
* is to clear out the password field.
*/
{
Log(("VBoxCredential::SetDeselected\n"));
if (m_rgFieldStrings[SFI_PASSWORD])
{
// CoTaskMemFree (below) deals with NULL, but StringCchLength does not.
{
SecureZeroMemory(m_rgFieldStrings[SFI_PASSWORD], lenPassword * sizeof(*m_rgFieldStrings[SFI_PASSWORD]));
}
{
}
}
return hr;
}
/*
* Gets info for a particular field of a tile. Called by logonUI to get information to
* display the tile.
*/
{
Log(("VBoxCredential::GetFieldState: dwFieldID=%ld, pcpfs=%p, pcpfis=%p\n", dwFieldID, pcpfs, pcpfis));
&& pcpfs
&& pcpfis)
{
}
else
{
hr = E_INVALIDARG;
}
return hr;
}
/*
* Searches the account name based on a display (real) name (e.g. "John Doe" -> "jdoe").
* Result "ppwszAccoutName" needs to be freed with CoTaskMemFree!
*/
{
Log(("VBoxCredential::TranslateAccountName\n"));
Log(("VBoxCredential::TranslateAccountName: Getting account name for '%ls' ...\n", pwszDisplayName));
/** @todo Do we need ADS support (e.g. TranslateNameW) here? */
DWORD dwEntriesRead = 0;
DWORD dwTotalEntries = 0;
DWORD dwResumeHandle = 0;
do
{
if ( (nStatus == NERR_Success)
|| (nStatus == ERROR_MORE_DATA))
{
{
for (DWORD i = 0; i < dwEntriesRead; i++)
{
/*
* Search for the "display name" - that might be
* "John Doe" or something similar the user recognizes easier
* and may not the same as the "account" name (e.g. "jdoe").
*/
if ( pCurBuf
{
/*
* Copy the real user name (e.g. "jdoe") to our
* output buffer.
*/
{
}
else
break;
}
pCurBuf++;
}
}
{
}
}
{
}
Log(("VBoxCredential::TranslateAccountName: Returned nStatus=%ld, fFound=%s\n",
return fFound;
#if 0
&& cbLen > 0)
{
{
Log(("VBoxCredential::GetAccountName: Real ADS account name of '%ls' is '%ls'\n",
}
else
{
dwErr = GetLastError();
}
}
else
dwErr = GetLastError();
/* The above method for looking up in ADS failed, try another one. */
{
}
#endif
}
/* Sets ppwsz to the string value of the field at the index dwFieldID. */
{
/* Check to make sure dwFieldID is a legitimate index. */
&& ppwszString)
{
switch (dwFieldID)
{
/** @todo Add more specific field IDs here if needed. */
default:
/*
* Make a copy of the string and return that, the caller is responsible for freeing it.
* Note that there can be empty fields (like a missing domain name); handle them
* by writing an empty string.
*/
break;
}
}
else
hr = E_INVALIDARG;
return hr;
}
/*
* Sets pdwAdjacentTo to the index of the field the submit button should be
* adjacent to. We recommend that the submit button is placed next to the last
* field which the user is required to enter information in. Optional fields
* should be below the submit button.
*/
{
/* Validate parameters. */
{
/* pdwAdjacentTo is a pointer to the fieldID you want the submit button to appear next to. */
Log(("VBoxCredential::GetSubmitButtonValue: dwFieldID=%ld, *pdwAdjacentTo=%ld\n", dwFieldID, *pdwAdjacentTo));
}
else
{
hr = E_INVALIDARG;
}
return hr;
}
/*
* Sets the value of a field which can accept a string as a value.
* This is called on each keystroke when a user types into an edit field.
*/
{
Log(("VBoxCredential::SetStringValue: dwFieldID=%ld, pcwzString=%ls\n",
dwFieldID, pcwzString));
/*
* We don't set any values into fields (e.g. the password, hidden
* by dots), instead keep it secret by resetting all credentials.
*/
#if 0
/* Validate parameters. */
{
}
else
{
hr = E_INVALIDARG;
}
#else
#endif
return hr;
}
/*
* The following methods are for logonUI to get the values of various UI elements and then communicate
* to the credential about what the user did in that field. However, these methods are not implemented
* because our tile doesn't contain these types of UI elements.
*/
{
/* We don't do own bitmaps */
return E_NOTIMPL;
}
{
return E_NOTIMPL;
}
{
return E_NOTIMPL;
}
{
return E_NOTIMPL;
}
{
return E_NOTIMPL;
}
{
return E_NOTIMPL;
}
{
return E_NOTIMPL;
}
/*
* Collect the username and password into a serialized credential for the correct usage scenario
* LogonUI then passes these credentials back to the system to log on.
*/
HRESULT VBoxCredential::GetSerialization(CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE *pcpGetSerializationResponse,
{
Log(("VBoxCredential::GetSerialization: pcpGetSerializationResponse=%p, pcpCredentialSerialization=%p, ppwszOptionalStatusText=%p, pcpsiOptionalStatusIcon=%p\n",
pcpGetSerializationResponse, pcpCredentialSerialization, ppwszOptionalStatusText, pcpsiOptionalStatusIcon));
{
/* Is a domain name missing? Then use the name of the local computer. */
else
/* Fill in the username and password. */
{
{
{
/* Allocate copies of, and package, the strings in a binary blob. */
{
{
/*
* At this point the credential has created the serialized credential used for logon
* By setting this to CPGSR_RETURN_CREDENTIAL_FINISHED we are letting logonUI know
* that we have all the information we need and it should attempt to submit the
* serialized credential.
*/
}
}
}
}
}
}
else
{
}
return hr;
}
/*
* ReportResult is completely optional. Its purpose is to allow a credential to customize the string
* and the icon displayed in the case of a logon failure. For example, we have chosen to
* being disabled.
*/
{
/* Look for a match on status and substatus. */
{
if (s_rgLogonStatusInfo[i].ntsStatus == ntsStatus && s_rgLogonStatusInfo[i].ntsSubstatus == ntsSubstatus)
{
dwStatusInfo = i;
break;
}
}
{
}
/* Try to lookup a text message for error code. */
if (hNtDLL)
{
0,
NULL);
}
Log(("VBoxCredential::ReportResult: ntsStatus=%ld, ntsSubstatus=%ld, ppwszOptionalStatusText=%p, pcpsiOptionalStatusIcon=%p, dwStatusInfo=%ld, Message=%ls\n",
ntsStatus, ntsSubstatus, ppwszOptionalStatusText, pcpsiOptionalStatusIcon, dwStatusInfo, lpMessageBuffer ? lpMessageBuffer : L"<None>"));
/* Print to user-friendly message to release log. */
{
if (lpMessageBuffer)
/* Login attempt failed; reset and clear all data. */
Reset();
}
if (lpMessageBuffer)
/*
* Since NULL is a valid value for *ppwszOptionalStatusText and *pcpsiOptionalStatusIcon
* this function can't fail
*/
return S_OK;
}