/** @file
This Driver mainly provides Setup Form to change password.
Copyright (c) 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "UserAuthentication2Dxe.h"
USER_AUTHENTICATION_PRIVATE_DATA *mUserAuthenticationData = NULL;
EFI_GUID mUserAuthenticationVendorGuid = USER_AUTHENTICATION_FORMSET_GUID;
HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath = {
{
{
HARDWARE_DEVICE_PATH,
HW_VENDOR_DP,
{
(UINT8) (sizeof (VENDOR_DEVICE_PATH)),
(UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
}
},
USER_AUTHENTICATION_FORMSET_GUID
},
{
END_DEVICE_PATH_TYPE,
END_ENTIRE_DEVICE_PATH_SUBTYPE,
{
(UINT8) (END_DEVICE_PATH_LENGTH),
(UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
}
}
};
/**
Display a message box to end user.
@param[in] DisplayString The string in message box.
**/
VOID
MessageBox (
IN CHAR16 *DisplayString
)
{
EFI_INPUT_KEY Key;
do {
CreatePopUp (
EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
&Key,
L"",
DisplayString,
L"Press ENTER to continue ...",
L"",
NULL
);
} while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
}
/**
Force system reset.
**/
VOID
ForceSystemReset (
VOID
)
{
MessageBox (L"Password retry count reach, reset system!");
gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
CpuDeadLoop();
}
/**
Display message for set password.
@param[in] ReturnStatus The return status for set password.
**/
VOID
PrintSetPasswordStatus (
IN EFI_STATUS ReturnStatus
)
{
CHAR16 *DisplayString;
CHAR16 *DisplayString2;
EFI_INPUT_KEY Key;
if (ReturnStatus == EFI_UNSUPPORTED) {
DisplayString = L"New password is not strong enough!";
DisplayString2 = L"Password must at least 8 chars and include lowercase, uppercase alphabetic, number and symbol";
do {
CreatePopUp (
EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
&Key,
L"",
DisplayString,
DisplayString2,
L"Press ENTER to continue ...",
L"",
NULL
);
} while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
} else {
if (ReturnStatus == EFI_SUCCESS) {
DisplayString = L"New password is updated successfully!";
} else if (ReturnStatus == EFI_ALREADY_STARTED) {
DisplayString = L"New password is found in the history passwords!";
} else {
DisplayString = L"New password update fails!";
}
do {
CreatePopUp (
EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
&Key,
L"",
DisplayString,
L"Press ENTER to continue ...",
L"",
NULL
);
} while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
}
}
/**
This function allows a caller to extract the current configuration for one
or more named elements from the target driver.
@param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
@param Request A null-terminated Unicode string in
format.
@param Progress On return, points to a character in the Request
string. Points to the string's null terminator if
request was successful. Points to the most recent
'&' before the first failing name/value pair (or
the beginning of the string if the failure is in
the first name/value pair) if the request was not
successful.
@param Results A null-terminated Unicode string in
format which has all values filled
in for the names in the Request string. String to
be allocated by the called function.
@retval EFI_SUCCESS The Results is filled with the requested values.
@retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
@retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
@retval EFI_NOT_FOUND Routing data doesn't match any storage in this
driver.
**/
EFI_STATUS
EFIAPI
ExtractConfig (
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
IN CONST EFI_STRING Request,
OUT EFI_STRING *Progress,
OUT EFI_STRING *Results
)
{
if (Progress == NULL || Results == NULL) {
return EFI_INVALID_PARAMETER;
}
*Progress = Request;
return EFI_NOT_FOUND;
}
/**
This function processes the results of changes in configuration.
@param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
@param Configuration A null-terminated Unicode string in
format.
@param Progress A pointer to a string filled in with the offset of
the most recent '&' before the first failing
name/value pair (or the beginning of the string if
the failure is in the first name/value pair) or
the terminating NULL if all was successful.
@retval EFI_SUCCESS The Results is processed successfully.
@retval EFI_INVALID_PARAMETER Configuration is NULL.
@retval EFI_NOT_FOUND Routing data doesn't match any storage in this
driver.
**/
EFI_STATUS
EFIAPI
RouteConfig (
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
IN CONST EFI_STRING Configuration,
OUT EFI_STRING *Progress
)
{
if (Configuration == NULL || Progress == NULL) {
return EFI_INVALID_PARAMETER;
}
*Progress = Configuration;
return EFI_NOT_FOUND;
}
/**
HII update Admin Password status.
**/
VOID
HiiUpdateAdminPasswordStatus (
VOID
)
{
if (IsPasswordInstalled ()) {
HiiSetString (
mUserAuthenticationData->HiiHandle,
STRING_TOKEN (STR_ADMIN_PASSWORD_STS_CONTENT),
L"Installed",
NULL
);
} else {
HiiSetString (
mUserAuthenticationData->HiiHandle,
STRING_TOKEN (STR_ADMIN_PASSWORD_STS_CONTENT),
L"Not Installed",
NULL
);
}
}
/**
This function processes the results of changes in configuration.
@param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
@param Action Specifies the type of action taken by the browser.
@param QuestionId A unique value which is sent to the original
exporting driver so that it can identify the type
of data to expect.
@param Type The type of value for the question.
@param Value A pointer to the data being sent to the original
exporting driver.
@param ActionRequest On return, points to the action requested by the
callback function.
@retval EFI_SUCCESS The callback successfully handled the action.
@retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
variable and its data.
@retval EFI_DEVICE_ERROR The variable could not be saved.
@retval EFI_UNSUPPORTED The specified Action is not supported by the
callback.
**/
EFI_STATUS
EFIAPI
UserAuthenticationCallback (
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
IN EFI_BROWSER_ACTION Action,
IN EFI_QUESTION_ID QuestionId,
IN UINT8 Type,
IN EFI_IFR_TYPE_VALUE *Value,
OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
)
{
EFI_STATUS Status;
CHAR16 *UserInputPassword;
Status = EFI_SUCCESS;
if (((Value == NULL) && (Action != EFI_BROWSER_ACTION_FORM_OPEN) && (Action != EFI_BROWSER_ACTION_FORM_CLOSE)) ||
(ActionRequest == NULL)) {
return EFI_INVALID_PARAMETER;
}
switch (Action) {
case EFI_BROWSER_ACTION_FORM_OPEN:
{
switch (QuestionId) {
case ADMIN_PASSWORD_KEY_ID:
HiiUpdateAdminPasswordStatus ();
default:
break;
}
}
break;
case EFI_BROWSER_ACTION_CHANGING:
{
switch (QuestionId) {
case ADMIN_PASSWORD_KEY_ID:
if ((Type == EFI_IFR_TYPE_STRING) && (Value->string == 0) &&
(mUserAuthenticationData->PasswordState == BROWSER_STATE_SET_PASSWORD)) {
mUserAuthenticationData->PasswordState = BROWSER_STATE_VALIDATE_PASSWORD;
ZeroMem (mUserAuthenticationData->OldPassword, sizeof(mUserAuthenticationData->OldPassword));
return EFI_INVALID_PARAMETER;
}
//
// The Callback is responsible for validating old password input by user,
// If Callback return EFI_SUCCESS, it indicates validation pass.
//
switch (mUserAuthenticationData->PasswordState) {
case BROWSER_STATE_VALIDATE_PASSWORD:
UserInputPassword = HiiGetString (mUserAuthenticationData->HiiHandle, Value->string, NULL);
if (UserInputPassword == NULL) {
return EFI_UNSUPPORTED;
}
if ((StrLen (UserInputPassword) >= PASSWORD_MAX_SIZE)) {
Status = EFI_NOT_READY;
break;
}
if (UserInputPassword[0] == 0) {
//
// Setup will use an empty password to check whether the old password is set,
// If the validation is successful, means there is no old password, return
// success to set the new password. Or need to return EFI_NOT_READY to
// let user input the old password.
//
Status = VerifyPassword (UserInputPassword, StrSize (UserInputPassword));
if (Status == EFI_SUCCESS) {
mUserAuthenticationData->PasswordState = BROWSER_STATE_SET_PASSWORD;
} else {
Status = EFI_NOT_READY;
}
break;
}
Status = VerifyPassword (UserInputPassword, StrSize (UserInputPassword));
if (Status == EFI_SUCCESS) {
mUserAuthenticationData->PasswordState = BROWSER_STATE_SET_PASSWORD;
StrCpyS (
mUserAuthenticationData->OldPassword,
sizeof(mUserAuthenticationData->OldPassword)/sizeof(CHAR16),
UserInputPassword
);
} else {
//
// Old password mismatch, return EFI_NOT_READY to prompt for error message.
//
if (Status == EFI_ACCESS_DENIED) {
//
// Password retry count reach.
//
ForceSystemReset ();
}
Status = EFI_NOT_READY;
}
break;
case BROWSER_STATE_SET_PASSWORD:
UserInputPassword = HiiGetString (mUserAuthenticationData->HiiHandle, Value->string, NULL);
if (UserInputPassword == NULL) {
return EFI_UNSUPPORTED;
}
if ((StrLen (UserInputPassword) >= PASSWORD_MAX_SIZE)) {
Status = EFI_NOT_READY;
break;
}
Status = SetPassword (UserInputPassword, StrSize (UserInputPassword), mUserAuthenticationData->OldPassword, StrSize(mUserAuthenticationData->OldPassword));
PrintSetPasswordStatus (Status);
ZeroMem (mUserAuthenticationData->OldPassword, sizeof(mUserAuthenticationData->OldPassword));
mUserAuthenticationData->PasswordState = BROWSER_STATE_VALIDATE_PASSWORD;
HiiUpdateAdminPasswordStatus ();
break;
default:
break;
}
default:
break;
}
}
break;
default:
break;
}
return Status;
}
/**
User Authentication entry point.
@param ImageHandle The image handle.
@param SystemTable The system table.
@retval EFI_SUCCESS The entry point is executed successfully.
@return other Contain some other errors.
**/
EFI_STATUS
EFIAPI
UserAuthentication2Entry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_HANDLE DriverHandle;
EFI_HII_HANDLE HiiHandle;
DriverHandle = NULL;
mUserAuthenticationData = AllocateZeroPool (sizeof (USER_AUTHENTICATION_PRIVATE_DATA));
if (mUserAuthenticationData == NULL) {
return EFI_OUT_OF_RESOURCES;
}
mUserAuthenticationData->ConfigAccess.ExtractConfig = ExtractConfig;
mUserAuthenticationData->ConfigAccess.RouteConfig = RouteConfig;
mUserAuthenticationData->ConfigAccess.Callback = UserAuthenticationCallback;
mUserAuthenticationData->PasswordState = BROWSER_STATE_VALIDATE_PASSWORD;
//
// Install Config Access protocol to driver handle.
//
Status = gBS->InstallMultipleProtocolInterfaces (
&DriverHandle,
&gEfiDevicePathProtocolGuid,
&mHiiVendorDevicePath,
&gEfiHiiConfigAccessProtocolGuid,
&mUserAuthenticationData->ConfigAccess,
NULL
);
ASSERT_EFI_ERROR (Status);
mUserAuthenticationData->DriverHandle = DriverHandle;
//
// Add HII data to database.
//
HiiHandle = HiiAddPackages (
&mUserAuthenticationVendorGuid,
DriverHandle,
UserAuthentication2DxeStrings,
UserAuthenticationDxeVfrBin,
NULL
);
if (HiiHandle == NULL) {
return EFI_OUT_OF_RESOURCES;
}
mUserAuthenticationData->HiiHandle = HiiHandle;
return EFI_SUCCESS;
}
/**
Unloads the application and its installed protocol.
@param[in] ImageHandle Handle that identifies the image to be unloaded.
@retval EFI_SUCCESS The image has been unloaded.
**/
EFI_STATUS
EFIAPI
UserAuthentication2Unload (
IN EFI_HANDLE ImageHandle
)
{
ASSERT (mUserAuthenticationData != NULL);
//
// Uninstall Config Access Protocol.
//
if (mUserAuthenticationData->DriverHandle != NULL) {
gBS->UninstallMultipleProtocolInterfaces (
mUserAuthenticationData->DriverHandle,
&gEfiDevicePathProtocolGuid,
&mHiiVendorDevicePath,
&gEfiHiiConfigAccessProtocolGuid,
&mUserAuthenticationData->ConfigAccess,
NULL
);
mUserAuthenticationData->DriverHandle = NULL;
}
//
// Remove Hii Data.
//
if (mUserAuthenticationData->HiiHandle != NULL) {
HiiRemovePackages (mUserAuthenticationData->HiiHandle);
}
FreePool (mUserAuthenticationData);
mUserAuthenticationData = NULL;
return EFI_SUCCESS;
}