WinBioSetCredential function (winbio.h)
Saves a biometric logon credential for the current user. Starting with Windows 10, build 1607, this function is available to use with a mobile image.
Syntax
HRESULT WinBioSetCredential(
[in] WINBIO_CREDENTIAL_TYPE Type,
[in] PUCHAR Credential,
[in] SIZE_T CredentialSize,
[in] WINBIO_CREDENTIAL_FORMAT Format
);
Parameters
[in] Type
A WINBIO_CREDENTIAL_TYPE value that specifies the credential type. Currently, this can be WINBIO_CREDENTIAL_PASSWORD.
[in] Credential
A pointer to a variable length array of bytes that contains the credential. The format depends on the Type and Format parameters.
[in] CredentialSize
Size, in bytes, of the value specified by the Credential parameter.
[in] Format
A WINBIO_CREDENTIAL_FORMAT enumeration value that specifies the format of the credential. If the Type parameter is WINBIO_CREDENTIAL_PASSWORD, this can be one of the following:
Value | Meaning |
---|---|
|
The credential is a plaintext NULL-terminated Unicode string. |
|
The credential was wrapped by using the CredProtect function and packed by using the CredPackAuthenticationBuffer function. This is recommended. |
|
The password credential was wrapped with CredProtect. |
Return value
If the function succeeds, it returns S_OK. If the function fails, it returns an HRESULT value that indicates the error. Possible values include, but are not limited to, those in the following table. For a list of common error codes, see Common HRESULT Values.
Return code | Description |
---|---|
|
The caller does not have permission to set the credential. |
|
The user has not enrolled a biometric sample. |
|
The credential was not valid for the current user. |
|
Current administrative policy prohibits use of the credential provider. |
Remarks
If the current user has an existing logon credential of the specified type, WinBioSetCredential will overwrite it. The function verifies both the user credential and interactive logon privileges and fails if verification fails. An event related to the logon attempt is placed in the event log. Credentials for domain accounts can be saved only if permitted by Group Policy.
You should call SecureZeroMemory to securely zero the credential if you pass WINBIO_PASSWORD_PACKED in the Format parameter.
Only medium and higher integrity processes can set credentials. If a lower integrity process attempts to set credentials, the function returns E_ACCESSDENIED.
Examples
The following function retrieves the identity and credentials of the current user and then calls WinBioSetCredential to set the credentials. Two helper functions, GetCredentials and GetCurrentUserIdentity, are also included. Link to the Winbio.lib static library and include the following header files:
- Windows.h
- Wincred.h
- Stdio.h
- Conio.h
- Winbio.h
HRESULT SetCredential()
{
// Declare variables.
HRESULT hr = S_OK;
PVOID pvAuthBlob = NULL;
ULONG cbAuthBlob = 0;
WINBIO_IDENTITY identity;
PSID pSid = NULL;
// Find the identity of the user.
wprintf_s(L"\n Finding user identity.\n");
hr = GetCurrentUserIdentity( &identity );
if (FAILED(hr))
{
wprintf_s(L"\n User identity not found. hr = 0x%x\n", hr);
return hr;
}
// Set a pointer to the security descriptor for the user.
pSid = identity.Value.AccountSid.Data;
// Retrieve a byte array that contains credential information.
hr = GetCredentials(pSid, &pvAuthBlob, &cbAuthBlob);
if (FAILED(hr))
{
wprintf_s(L"\n GetCredentials failed. hr = 0x%x\n", hr);
goto e_Exit;
}
// Set the credentials.
hr = WinBioSetCredential(
WINBIO_CREDENTIAL_PASSWORD, // Type of credential.
(PUCHAR)pvAuthBlob, // Credentials byte array
cbAuthBlob, // Size of credentials
WINBIO_PASSWORD_PACKED); // Credentials format
if (FAILED(hr))
{
wprintf_s(L"\n WinBioSetCredential failed. hr = 0x%x\n", hr);
goto e_Exit;
}
wprintf_s(L"\n Credentials successfully set.\n");
e_Exit:
// Delete the authentication byte array.
if (NULL != pvAuthBlob)
{
SecureZeroMemory(pvAuthBlob, cbAuthBlob);
CoTaskMemFree(pvAuthBlob);
pvAuthBlob = NULL;
}
wprintf_s(L"\n Press any key to exit...");
_getch();
return hr;
}
//------------------------------------------------------------------------
// The following function displays a dialog box to prompt a user
// for credentials.
//
HRESULT GetCredentials(PSID pSid, PVOID* ppvAuthBlob, ULONG* pcbAuthBlob)
{
HRESULT hr = S_OK;
DWORD dwResult;
WCHAR szUsername[MAX_PATH] = {0};
DWORD cchUsername = ARRAYSIZE(szUsername);
WCHAR szPassword[MAX_PATH] = {0};
WCHAR szDomain[MAX_PATH] = {0};
DWORD cchDomain = ARRAYSIZE(szDomain);
WCHAR szDomainAndUser[MAX_PATH] = {0};
DWORD cchDomainAndUser = ARRAYSIZE(szDomainAndUser);
PVOID pvInAuthBlob = NULL;
ULONG cbInAuthBlob = 0;
PVOID pvAuthBlob = NULL;
ULONG cbAuthBlob = 0;
CREDUI_INFOW ui;
ULONG ulAuthPackage = 0;
BOOL fSave = FALSE;
static const WCHAR WINBIO_CREDPROV_TEST_PASSWORD_PROMPT_MESSAGE[] =
L"Enter your current password to enable biometric logon.";
static const WCHAR WINBIO_CREDPROV_TEST_PASSWORD_PROMPT_CAPTION[] =
L"Biometric Log On Enrollment";
if (NULL == pSid || NULL == ppvAuthBlob || NULL == pcbAuthBlob)
{
return E_INVALIDARG;
}
// Retrieve the user name and domain name.
SID_NAME_USE SidUse;
DWORD cchTmpUsername = cchUsername;
DWORD cchTmpDomain = cchDomain;
if (!LookupAccountSidW(
NULL, // Local computer
pSid, // Security identifier for user
szUsername, // User name
&cchTmpUsername, // Size of user name
szDomain, // Domain name
&cchTmpDomain, // Size of domain name
&SidUse)) // Account type
{
dwResult = GetLastError();
hr = HRESULT_FROM_WIN32(dwResult);
wprintf_s(L"\n LookupAccountSidLocalW failed: hr = 0x%x\n", hr);
return hr;
}
// Combine the domain and user names.
swprintf_s(
szDomainAndUser,
cchDomainAndUser,
L"%s\\%s",
szDomain,
szUsername);
// Call CredPackAuthenticationBufferW once to determine the size,
// in bytes, of the authentication buffer.
if (!CredPackAuthenticationBufferW(
0, // Reserved
szDomainAndUser, // Domain\User name
szPassword, // User Password
NULL, // Packed credentials
&cbInAuthBlob) // Size, in bytes, of credentials
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
dwResult = GetLastError();
hr = HRESULT_FROM_WIN32(dwResult);
wprintf_s(L"\n CredPackAuthenticationBufferW (1) failed: ");
wprintf_s(L"hr = 0x%x\n", hr);
}
// Allocate memory for the input buffer.
pvInAuthBlob = CoTaskMemAlloc(cbInAuthBlob);
if (!pvInAuthBlob)
{
cbInAuthBlob = 0;
wprintf_s(L"\n CoTaskMemAlloc() Out of memory %d\n");
return HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
}
// Call CredPackAuthenticationBufferW again to retrieve the
// authentication buffer.
if (!CredPackAuthenticationBufferW(
0,
szDomainAndUser,
szPassword,
(PBYTE)pvInAuthBlob,
&cbInAuthBlob))
{
dwResult = GetLastError();
hr = HRESULT_FROM_WIN32(dwResult);
wprintf_s(L"\n CredPackAuthenticationBufferW (2) failed: ");
wprintf_s(L"hr = 0x%x\n", hr);
goto e_Exit;
}
// Display a dialog box to request credentials.
ui.cbSize = sizeof(ui);
ui.hwndParent = GetConsoleWindow();
ui.pszMessageText = WINBIO_CREDPROV_TEST_PASSWORD_PROMPT_MESSAGE;
ui.pszCaptionText = WINBIO_CREDPROV_TEST_PASSWORD_PROMPT_CAPTION;
ui.hbmBanner = NULL;
dwResult = CredUIPromptForWindowsCredentialsW(
&ui, // Customizing information
0, // Error code to display
&ulAuthPackage, // Authorization package
pvInAuthBlob, // Credential byte array
cbInAuthBlob, // Size of credential input buffer
&pvAuthBlob, // Output credential byte array
&cbAuthBlob, // Size of credential byte array
&fSave, // Select the save check box.
CREDUIWIN_IN_CRED_ONLY |
CREDUIWIN_ENUMERATE_CURRENT_USER
);
if (dwResult != NO_ERROR)
{
hr = HRESULT_FROM_WIN32(dwResult);
wprintf_s(L"\n CredUIPromptForWindowsCredentials failed: ");
wprintf_s(L"0x%08x\n", dwResult);
goto e_Exit;
}
*ppvAuthBlob = pvAuthBlob;
*pcbAuthBlob = cbAuthBlob;
e_Exit:
// Delete the input authentication byte array.
if (pvInAuthBlob)
{
SecureZeroMemory(pvInAuthBlob, cbInAuthBlob);
CoTaskMemFree(pvInAuthBlob);
pvInAuthBlob = NULL;
};
return hr;
}
//------------------------------------------------------------------------
// The following function retrieves the identity of the current user.
// This is a helper function and is not part of the Windows Biometric
// Framework API.
//
HRESULT GetCurrentUserIdentity(__inout PWINBIO_IDENTITY Identity)
{
// Declare variables.
HRESULT hr = S_OK;
HANDLE tokenHandle = NULL;
DWORD bytesReturned = 0;
struct{
TOKEN_USER tokenUser;
BYTE buffer[SECURITY_MAX_SID_SIZE];
} tokenInfoBuffer;
// Zero the input identity and specify the type.
ZeroMemory( Identity, sizeof(WINBIO_IDENTITY));
Identity->Type = WINBIO_ID_TYPE_NULL;
// Open the access token associated with the
// current process
if (!OpenProcessToken(
GetCurrentProcess(), // Process handle
TOKEN_READ, // Read access only
&tokenHandle)) // Access token handle
{
DWORD win32Status = GetLastError();
wprintf_s(L"Cannot open token handle: %d\n", win32Status);
hr = HRESULT_FROM_WIN32(win32Status);
goto e_Exit;
}
// Zero the tokenInfoBuffer structure.
ZeroMemory(&tokenInfoBuffer, sizeof(tokenInfoBuffer));
// Retrieve information about the access token. In this case,
// retrieve a SID.
if (!GetTokenInformation(
tokenHandle, // Access token handle
TokenUser, // User for the token
&tokenInfoBuffer.tokenUser, // Buffer to fill
sizeof(tokenInfoBuffer), // Size of the buffer
&bytesReturned)) // Size needed
{
DWORD win32Status = GetLastError();
wprintf_s(L"Cannot query token information: %d\n", win32Status);
hr = HRESULT_FROM_WIN32(win32Status);
goto e_Exit;
}
// Copy the SID from the tokenInfoBuffer structure to the
// WINBIO_IDENTITY structure.
CopySid(
SECURITY_MAX_SID_SIZE,
Identity->Value.AccountSid.Data,
tokenInfoBuffer.tokenUser.User.Sid
);
// Specify the size of the SID and assign WINBIO_ID_TYPE_SID
// to the type member of the WINBIO_IDENTITY structure.
Identity->Value.AccountSid.Size = GetLengthSid(tokenInfoBuffer.tokenUser.User.Sid);
Identity->Type = WINBIO_ID_TYPE_SID;
e_Exit:
if (tokenHandle != NULL)
{
CloseHandle(tokenHandle);
}
return hr;
}
Requirements
Requirement | Value |
---|---|
Minimum supported client | Windows 8.1 [desktop apps only] |
Minimum supported server | Windows Server 2012 R2 [desktop apps only] |
Target Platform | Windows |
Header | winbio.h (include Winbio.h) |
Library | Winbio.lib |
DLL | Winbio.dll |