alder_lake_bios/Oem/L05/FeatureCommon/InsydeL05ModulePkg/WmiSetupUnderOsSmm/WmiSetBiosPasswordA6.c

1534 lines
40 KiB
C

/** @file
;******************************************************************************
;* Copyright (c) 2018, Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
#include "WmiSetupUnderOsSmm.h"
BOOLEAN mAdminPasswordExist = FALSE;
BOOLEAN mUserPasswordExist = FALSE;
BOOLEAN mHddPasswordExist = FALSE;
BOOLEAN mPasswordChange = FALSE;
UINTN mPasswordErrorCount = 0;
WMI_PASSWORD_DATA_MAP mPasswordCheckData;
//
// Hexadecimal to Unicode char
//
STATIC UINT16 HexToChar16[] = {
L'0',
L'1',
L'2',
L'3',
L'4',
L'5',
L'6',
L'7',
L'8',
L'9',
L'A',
L'B',
L'C',
L'D',
L'E',
L'F'
};
//
// Refer from EFI_KEYBOARD_SCANCODE_LIST at SetupMenuService.c
//
// WMI keyboard scancode list
//
WMI_KEYBOARD_SCANCODE_LIST mScanCodeMap[] = {
{'a', 0x1E},
{'b', 0x30},
{'c', 0x2E},
{'d', 0x20},
{'e', 0x12},
{'f', 0x21},
{'g', 0x22},
{'h', 0x23},
{'i', 0x17},
{'j', 0x24},
{'k', 0x25},
{'l', 0x26},
{'m', 0x32},
{'n', 0x31},
{'o', 0x18},
{'p', 0x19},
{'q', 0x10},
{'r', 0x13},
{'s', 0x1F},
{'t', 0x14},
{'u', 0x16},
{'v', 0x2F},
{'w', 0x11},
{'x', 0x2D},
{'y', 0x15},
{'z', 0x2C},
{'1', 0x02},
{'2', 0x03},
{'3', 0x04},
{'4', 0x05},
{'5', 0x06},
{'6', 0x07},
{'7', 0x08},
{'8', 0x09},
{'9', 0x0A},
{'0', 0x0B},
#ifdef L05_SMB_BIOS_ENABLE
{' ', 0x39},
#endif
};
//
// WMI password type map
//
WMI_PASSWORD_TYPE_MAP mWmiPasswordTypeMap[] = {
// PasswordType, PasswordTypeStr
{WmiSystemAdminType, WMI_BIOS_PASSWORD_ADMIN_TYPE },
{WmiSystemUserType, WMI_BIOS_PASSWORD_USER_TYPE },
{WmiHddUserType, WMI_BIOS_PASSWORD_HDD_USER_TYPE },
{WmiHddMasterType, WMI_BIOS_PASSWORD_HDD_MASTER_TYPE},
};
//
// WMI password encoding map
//
WMI_PASSWORD_ENCODING_MAP mWmiPasswordEncodingMap[] = {
// PasswordEncoding, PasswordEncodingStr
{WmiAsciiEncoding, WMI_BIOS_PASSWORD_ASCII_ENCODING },
{WmiScancodeEncoding, WMI_BIOS_PASSWORD_SCANCODE_ENCODING},
};
//
// WMI password language map
//
WMI_PASSWORD_LANGUAGE_MAP mWmiPasswordLanguageMap[] = {
// PasswordLanguage, PasswordLanguageStr
{WmiUsLanguage, WMI_BIOS_PASSWORD_US_LANGUAGE},
{WmiFrLanguage, WMI_BIOS_PASSWORD_FR_LANGUAGE},
{WmiGrLanguage, WMI_BIOS_PASSWORD_GR_LANGUAGE},
};
//
// Map List Count
//
UINT16 mWmiPasswordTypeMapListCount = sizeof (mWmiPasswordTypeMap) / sizeof (WMI_PASSWORD_TYPE_MAP);
UINT16 mWmiPasswordEncodingMapListCount = sizeof (mWmiPasswordEncodingMap) / sizeof (WMI_PASSWORD_ENCODING_MAP);
UINT16 mWmiPasswordLanguageMapListCount = sizeof (mWmiPasswordLanguageMap) / sizeof (WMI_PASSWORD_LANGUAGE_MAP);
/**
Refer from ConvertUnicodeCharToKeyboardScancode() at SetupMenuService.c
Convert Ascii Char to Keyboard Scancode(Normal).
@param KeyData Point to Key Data(Ascii).
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_NOT_FOUND The Ascii Char can't map to Keyboard Scancode.
**/
EFI_STATUS
ConvertAsciiCharToKeyboardScancode (
OUT CHAR8 *KeyData
)
{
UINTN Index;
for (Index = 0; Index < (sizeof (mScanCodeMap) / sizeof (WMI_KEYBOARD_SCANCODE_LIST)); Index++) {
#ifdef L05_SMB_BIOS_ENABLE
//
// [Lenovo SMB BIOS Special Requirements V1.1]
// 2.1 BIOS Password Characters
// Supported characters
// - Alphabet (case insensitive)
//
if (*KeyData >= L'A' && *KeyData <= L'Z') {
*KeyData += 0x20;
}
#endif
if (*KeyData == mScanCodeMap[Index].AsciiChar) {
*KeyData = mScanCodeMap[Index].KeyboardScanCode;
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}
/**
This function uses to check password type.
@param PasswordTypeStr A pointer to the password type string.
@param PasswordType A pointer to the system admin password or user password.
@retval TRUE Password type is valid.
@retval FALSE Password type is not valid.
**/
BOOLEAN
CheckPasswordTypeIsValid (
IN CHAR8 *PasswordTypeStr,
OUT WMI_PASSWORD_TYPE *PasswordType
)
{
BOOLEAN IsValid;
UINTN Index;
//
// Initialization
//
IsValid = FALSE;
//
// Compare password type string to get password type
//
for (Index = 0; Index < mWmiPasswordTypeMapListCount; Index++) {
if (AsciiStrnCmp (PasswordTypeStr, mWmiPasswordTypeMap[Index].PasswordTypeStr, AsciiStrLen (mWmiPasswordTypeMap[Index].PasswordTypeStr)) == 0) {
*PasswordType = mWmiPasswordTypeMap[Index].PasswordType;
IsValid = TRUE;
break;
}
}
return IsValid;
}
/**
Refer from IsValidKeyData() at SetupMenuService.c
Check password is valid.
@param Password A pointer to the Password buffer.
@param PasswordType Type of password.
@retval TRUE Password is valid.
@retval FALSE Password is not valid.
**/
BOOLEAN
CheckPasswordIsValid (
IN CHAR8 **Password,
IN WMI_PASSWORD_TYPE PasswordType
)
{
BOOLEAN IsValid;
EFI_STATUS Status;
UINTN MaxPasswordLen;
UINTN Index;
//
// Initialization
//
IsValid = TRUE;
MaxPasswordLen = 0;
//
// Step 1. Check password length
//
switch (PasswordType) {
case WmiSystemAdminType:
case WmiSystemUserType:
MaxPasswordLen = L05_WMI_PASSWORD_MAX_LENGTH;
break;
case WmiHddUserType:
case WmiHddMasterType:
MaxPasswordLen = HDD_PASSWORD_MAX_NUMBER;
break;
}
if (AsciiStrLen (*Password) > MaxPasswordLen) {
IsValid = FALSE;
}
//
// Step 2. Only 'a'~'z', '0'~'9' are valid key data for password Character
//
for (Index = 0; Index < AsciiStrLen (*Password); Index++) {
if (((*Password)[Index] < L'a' || (*Password)[Index] > L'z')
&& ((*Password)[Index] < L'0' || (*Password)[Index] > L'9')
#ifdef L05_SMB_BIOS_ENABLE
//
// [Lenovo SMB BIOS Special Requirements V1.1]
// 2.1 BIOS Password Characters
// Supported characters
// - Alphabet (case insensitive)
// - Space ' '
//
&& ((*Password)[Index] < L'A' || (*Password)[Index] > L'Z')
&& ((*Password)[Index] != L' ')
#endif
) {
IsValid = FALSE;
break;
}
//
// Step 3. Convert ASCII char to keyboard scancode
//
Status = ConvertAsciiCharToKeyboardScancode (&((*Password)[Index]));
if (EFI_ERROR (Status)) {
IsValid = FALSE;
break;
}
}
return IsValid;
}
/**
This function uses to check password encoding.
@param PasswordEncodingStr A pointer to the password encoding string.
@param PasswordEncoding A pointer to the password encoding.
@retval TRUE Password encoding is valid.
@retval FALSE Password encoding is not valid.
**/
BOOLEAN
CheckPasswordEncodingIsValid (
IN CHAR8 *PasswordEncodingStr,
OUT WMI_PASSWORD_TYPE *PasswordEncoding
)
{
BOOLEAN IsValid;
UINTN Index;
//
// Initialization
//
IsValid = FALSE;
//
// Compare password encoding string to get password encoding
//
for (Index = 0; Index < mWmiPasswordEncodingMapListCount; Index++) {
if (AsciiStrCmp (PasswordEncodingStr, mWmiPasswordEncodingMap[Index].PasswordEncodingStr) == 0) {
*PasswordEncoding = mWmiPasswordEncodingMap[Index].PasswordEncoding;
IsValid = TRUE;
break;
}
}
return IsValid;
}
/**
This function uses to check password language.
@param PasswordLanguageStr A pointer to the password language string.
@param PasswordLanguage A pointer to the password language.
@retval TRUE Password language is valid.
@retval FALSE Password language is not valid.
**/
BOOLEAN
CheckPasswordLanguageIsValid (
IN CHAR8 *PasswordLanguageStr,
OUT WMI_PASSWORD_LANGUAGE *PasswordLanguage
)
{
BOOLEAN IsValid;
UINTN Index;
//
// Initialization
//
IsValid = FALSE;
//
// Compare password language string to get password language
//
for (Index = 0; Index < mWmiPasswordLanguageMapListCount; Index++) {
if (AsciiStrCmp (PasswordLanguageStr, mWmiPasswordLanguageMap[Index].PasswordLanguageStr) == 0) {
*PasswordLanguage = mWmiPasswordLanguageMap[Index].PasswordLanguage;
IsValid = TRUE;
break;
}
}
return IsValid;
}
/**
Analyze WMI set password input buffer.
@param PasswordType Assign a pointer to the password type.
@param CurrentPassword Assign a pointer to the current password.
@param NewPassword Assign a pointer to the new password.
@param PasswordEncodingStr Assign a pointer to the password encoding string.
@param PasswordLanguageStr Assign a pointer to the password keyboard language string.
@retval EFI_SUCCESS This function execute successfully.
@retval Others An unexpected error occurred.
**/
EFI_STATUS
AnalyzeWmiSetPasswordInputBuffer (
OUT CHAR8 **PasswordType,
OUT CHAR8 **CurrentPassword,
OUT CHAR8 **NewPassword,
OUT CHAR8 **PasswordEncodingStr,
OUT CHAR8 **PasswordLanguageStr
)
{
EFI_STATUS Status;
UINTN BufferOffset;
UINTN TempBufferOffset;
UINTN SectionCount;
//
// Initialization
//
Status = EFI_INVALID_PARAMETER;
BufferOffset = 0;
//
// Part section
//
SectionCount = 0;
TempBufferOffset = 0;
for (BufferOffset = 0; BufferOffset < mL05GlobalNVSArea->L05WmiBufferLen; BufferOffset++) {
if ((mL05GlobalNVSArea->L05WmiBuffer[BufferOffset] != ',')
&&(mL05GlobalNVSArea->L05WmiBuffer[BufferOffset] != ';')) {
continue;
}
mL05GlobalNVSArea->L05WmiBuffer[BufferOffset] = 0;
switch (SectionCount) {
case SetBiosPasswordType:
*PasswordType = &mL05GlobalNVSArea->L05WmiBuffer[TempBufferOffset];
break;
case SetBiosPasswordCurrentPassword:
*CurrentPassword = &mL05GlobalNVSArea->L05WmiBuffer[TempBufferOffset];
break;
case SetBiosPasswordNewPassword:
*NewPassword = &mL05GlobalNVSArea->L05WmiBuffer[TempBufferOffset];
break;
case SetBiosPasswordEncoding:
*PasswordEncodingStr = &mL05GlobalNVSArea->L05WmiBuffer[TempBufferOffset];
break;
case SetBiosPasswordLanguage:
*PasswordLanguageStr = &mL05GlobalNVSArea->L05WmiBuffer[TempBufferOffset];
break;
}
TempBufferOffset = BufferOffset;
TempBufferOffset++;
SectionCount++;
}
//
// Check section number is valid
//
if (SectionCount == SetBiosPasswordMaxSection) {
Status = EFI_SUCCESS;
}
return Status;
}
/**
Check WMI password format.
@param PasswordTypeStr A pointer to the password type string.
@param PasswordType A pointer to the password type.
@param PasswordEncodingStr A pointer to the password encoding string.
@param PasswordEncoding A pointer to the password encoding.
@param PasswordLanguageStr A pointer to the password keyboard language string.
@param PasswordLanguage A pointer to the password keyboard language.
@retval EFI_SUCCESS This function execute successfully.
@retval EFI_INVALID_PARAMETER Input invalid password format.
@retval EFI_ACCESS_DENIED Input invalid password rule.
**/
EFI_STATUS
CheckWmiPasswordFormat (
IN CHAR8 *PasswordTypeStr,
OUT WMI_PASSWORD_TYPE *PasswordType,
IN CHAR8 *PasswordEncodingStr,
IN OUT WMI_PASSWORD_ENCODING *PasswordEncoding,
IN CHAR8 *PasswordLanguageStr,
IN OUT WMI_PASSWORD_LANGUAGE *PasswordLanguage
)
{
EFI_STATUS Status;
//
// Initialization
//
Status = EFI_SUCCESS;
//
// Check password type is valid
//
if (!CheckPasswordTypeIsValid (PasswordTypeStr, PasswordType)) {
Status = EFI_INVALID_PARAMETER;
return Status;
}
//
// Check password encoding is valid
//
if (!CheckPasswordEncodingIsValid (PasswordEncodingStr, PasswordEncoding)) {
Status = EFI_INVALID_PARAMETER;
return Status;
}
//
// L05 only support ascii encoding
//
if (*PasswordEncoding != WmiAsciiEncoding) {
Status = EFI_UNSUPPORTED;
return Status;
}
//
// Check password keyboard languages is valid
//
if (!CheckPasswordLanguageIsValid (PasswordLanguageStr, PasswordLanguage)) {
Status = EFI_INVALID_PARAMETER;
return Status;
}
//
// L05 only support us language
//
if (*PasswordLanguage != WmiUsLanguage) {
Status = EFI_UNSUPPORTED;
return Status;
}
return Status;
}
/**
Check WMI password input buffer.
@param PasswordTypeStr A pointer to the password type string.
@param PasswordType A pointer to the password type.
@param CurrentPassword A pointer to the current password.
@param NewPassword A pointer to the new password.
@param PasswordEncodingStr A pointer to the password encoding string.
@param PasswordEncoding A pointer to the password encoding.
@param PasswordLanguageStr A pointer to the password keyboard language string.
@param PasswordLanguage A pointer to the password keyboard language.
@retval EFI_SUCCESS This function execute successfully.
@retval EFI_INVALID_PARAMETER Input invalid password format.
@retval EFI_ACCESS_DENIED Input invalid password rule.
**/
EFI_STATUS
CheckWmiPasswordInputBuffer (
IN CHAR8 *PasswordTypeStr,
OUT WMI_PASSWORD_TYPE *PasswordType,
IN OUT CHAR8 *CurrentPassword,
IN OUT CHAR8 *NewPassword,
IN CHAR8 *PasswordEncodingStr,
IN OUT WMI_PASSWORD_ENCODING *PasswordEncoding,
IN CHAR8 *PasswordLanguageStr,
IN OUT WMI_PASSWORD_LANGUAGE *PasswordLanguage
)
{
EFI_STATUS Status;
//
// Initialization
//
Status = EFI_SUCCESS;
//
// Check WMI password format
//
Status = CheckWmiPasswordFormat (
PasswordTypeStr,
PasswordType,
PasswordEncodingStr,
PasswordEncoding,
PasswordLanguageStr,
PasswordLanguage
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check current password is valid
//
if (!CheckPasswordIsValid (&CurrentPassword, *PasswordType)) {
Status = EFI_INVALID_PARAMETER;
return Status;
}
//
// Check NewPassword password is valid
//
if (!CheckPasswordIsValid (&NewPassword, *PasswordType)) {
Status = EFI_INVALID_PARAMETER;
return Status;
}
//
// [Lenovo BIOS Setup using WMI Deployment Guide - Third Edition (February 2016)]
// 2. A password cannot be set using this method when one does not already exist.
// Passwords can only be updated or cleared.
//
if (AsciiStrLen (CurrentPassword) == 0) {
Status = EFI_ACCESS_DENIED;
return Status;
}
//
// [Lenovo China Minimum BIOS Spec Version 1.37]
// [3.4.1 Rules for BIOS CMOS password]
// When user did not set any password,the security menu have one submenu:
// Set Administrator Password.
//
if (!mAdminPasswordExist && (*PasswordType == WmiSystemUserType)) {
Status = EFI_ACCESS_DENIED;
return Status;
}
return Status;
}
/**
Check WMI input password is repeat.
@param None
@retval TRUE WMI input password is repeat.
@retval FALSE WMI input password is not repeat.
**/
BOOLEAN
WmiInputPasswordIsRepeat (
VOID
)
{
EFI_STATUS Status;
CHAR8 *PasswordTypeStr;
WMI_PASSWORD_TYPE PasswordType;
CHAR8 *CurrentPassword;
CHAR8 *NewPassword;
CHAR8 *PasswordEncodingStr;
WMI_PASSWORD_ENCODING PasswordEncoding;
CHAR8 *PasswordLanguageStr;
WMI_PASSWORD_LANGUAGE PasswordLanguage;
//
// Initialization
//
Status = EFI_SUCCESS;
PasswordTypeStr = NULL;
PasswordType = WmiPasswoedMaxType;
CurrentPassword = NULL;
NewPassword = NULL;
PasswordEncodingStr = NULL;
PasswordEncoding = WmiPasswoedMaxEncoding;
PasswordLanguageStr = NULL;
PasswordLanguage = WmiPasswoedMaxLanguage;
//
// Analyze WMI set password input buffer
//
Status = AnalyzeWmiSetPasswordInputBuffer (
&PasswordTypeStr,
&CurrentPassword,
&NewPassword,
&PasswordEncodingStr,
&PasswordLanguageStr
);
if (EFI_ERROR (Status)) {
return FALSE;
}
//
// Check WMI password input buffer is valid
//
Status = CheckWmiPasswordInputBuffer (
PasswordTypeStr,
&PasswordType,
CurrentPassword,
NewPassword,
PasswordEncodingStr,
&PasswordEncoding,
PasswordLanguageStr,
&PasswordLanguage
);
if (EFI_ERROR (Status)) {
return FALSE;
}
//
// Check password type is the same
//
if (PasswordType != mPasswordCheckData.PasswordType) {
return FALSE;
}
//
// Check current password is the same
//
if (AsciiStrCmp (CurrentPassword, mPasswordCheckData.CurrentPassword) != 0) {
return FALSE;
}
//
// Check new password is the same
//
if (AsciiStrCmp (NewPassword, mPasswordCheckData.NewPassword) != 0) {
return FALSE;
}
//
// Clean password check data
//
ZeroMem (&mPasswordCheckData, sizeof (WMI_PASSWORD_DATA_MAP));
return TRUE;
}
/**
Refer from ReadPassword() at SysPasswordDxe.c
WMI get admin or user password.
@param PasswordType System admin or user password.
@param Password Assign a pointer to the password buffer.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_UNSUPPORTED Invalid system password type.
**/
EFI_STATUS
EFIAPI
WmiReadPassword (
IN WMI_PASSWORD_TYPE PasswordType,
OUT UINT8 **Password
)
{
EFI_STATUS Status;
UINTN DataSize;
//
// Initialization
//
#ifndef L05_NOTEBOOK_PASSWORD_ENABLE
DataSize = L05_WMI_PASSWORD_MAX_LENGTH + 2;
#else
DataSize = SHA256_DIGEST_SIZE;
#endif
//
// Allocate resources
//
*Password = AllocateRuntimeZeroPool (DataSize);
//
// Get system passwords by password type
//
Status = OemSvcGetSystemPasswords (PasswordType, DataSize, *Password);
if (Status != EFI_MEDIA_CHANGED) {
return EFI_NOT_FOUND;
}
return EFI_SUCCESS;
}
/**
Refer from GetPasswordStatus() at SysPasswordDxe.c
Check admin or user password is set or not.
@param PasswordType System admin or user password.
@retval EFI_SUCCESS Password is set.
@retval EFI_NOT_FOUND Password isn't set.
**/
EFI_STATUS
EFIAPI
WmiGetPasswordStatus (
IN WMI_PASSWORD_TYPE PasswordType
)
{
EFI_STATUS Status;
UINT8 *Password;
//
// Initialization
//
Password = NULL;
//
// Read password by password type
//
Status = WmiReadPassword (PasswordType, &Password);
if (EFI_ERROR (Status) || (Password == NULL)) {
if (Password != NULL) {
FreePool (Password);
}
return Status;
}
#ifndef L05_NOTEBOOK_PASSWORD_ENABLE
//
// Check password Checksum is valid
//
if (!IsSystemPasswordChecksumValid (Password)) {
#else
//
// Check system has system password or not.
//
if (!L05HaveSystemPassword (Password)) {
#endif
FreePool (Password);
return EFI_NOT_FOUND;
}
//
// Free resources
//
FreePool (Password);
return EFI_SUCCESS;
}
/**
Refer from IsPasswordExist() at Password.c
This function uses to check admin password is exist.
@param None
@retval TRUE Admin password is in locked state.
@retval FALSE Admin password is in unloced state.
**/
BOOLEAN
WmiIsAdminPasswordExist (
VOID
)
{
EFI_STATUS Status;
Status = WmiGetPasswordStatus (WmiSystemAdminType);
return Status == EFI_SUCCESS ? TRUE : FALSE;
}
/**
Refer from IsPasswordExist() at Password.c
This function uses to check user password is exist.
@param None
@retval TRUE User password is in locked state.
@retval FALSE User password is in unloced state.
**/
BOOLEAN
WmiIsUserPasswordExist (
VOID
)
{
EFI_STATUS Status;
Status = WmiGetPasswordStatus (WmiSystemUserType);
return Status == EFI_SUCCESS ? TRUE : FALSE;
}
/**
This function uses to check HDD password is exist.
@param None
@retval TRUE Hdd password is in locked state.
@retval FALSE Hdd password is in unloced state.
**/
BOOLEAN
WmiIsHddPasswordExist (
VOID
)
{
EFI_STATUS Status;
HDD_PASSWORD_TABLE *HddPasswordTable;
UINTN HddPasswordTableSize;
//
// Initialization
//
Status = EFI_SUCCESS;
HddPasswordTableSize = 0;
HddPasswordTable = NULL;
//
// Get save HDD password
//
HddPasswordTable = SmmGetVariableAndSize (
SAVE_HDD_PASSWORD_VARIABLE_NAME,
&gSaveHddPasswordGuid,
&HddPasswordTableSize
);
if (HddPasswordTable == NULL) {
Status = EFI_NOT_FOUND;
}
//
// Free resources
//
if (HddPasswordTable != NULL) {
FreePool (HddPasswordTable);
}
return Status == EFI_SUCCESS ? TRUE : FALSE;
}
/**
Refer from CheckPassword() at SysPasswordDxe.c
Check admin or user password is correct or not.
@param None
@param PasswordType System admin or user password.
@param Password A pointer to the password.
@retval
**/
EFI_STATUS
WmiCheckPassword (
WMI_PASSWORD_TYPE PasswordType,
CHAR8 *Password
)
{
EFI_STATUS Status;
UINT8 *SavePassword;
//
// Initialization
//
SavePassword = NULL;
//
// Read password by password type
//
Status = WmiReadPassword (PasswordType, &SavePassword);
if (EFI_ERROR (Status) || (SavePassword == NULL)) {
if (SavePassword != NULL) {
FreePool (SavePassword);
}
return Status;
}
#ifndef L05_NOTEBOOK_PASSWORD_ENABLE
//
// Check password Checksum is valid
//
if (!IsSystemPasswordChecksumValid (SavePassword)) {
#else
//
// Check system has system password or not.
//
if (!L05HaveSystemPassword (SavePassword)) {
#endif
FreePool (SavePassword);
return EFI_NOT_FOUND;
}
//
// Compare input password with save password
//
if (!L05PasswordCmp (Password, SavePassword)) {
Status = EFI_CRC_ERROR;
}
//
// Free resources
//
FreePool (SavePassword);
return Status;
}
/**
Clear System password.
@param PasswordType System admin or user password.
@retval EFI_SUCCESS This function execute successfully.
@retval Others An unexpected error occurred.
**/
EFI_STATUS
ClearSystemPassword (
WMI_PASSWORD_TYPE PasswordType
)
{
EFI_STATUS Status;
#ifndef L05_NOTEBOOK_PASSWORD_ENABLE
UINT8 EmptyPassword[2];
#else
UINT8 EmptyPassword[SHA256_DIGEST_SIZE];
#endif
//
// Initialization
//
Status = EFI_SUCCESS;
//
// Clear Password
//
ZeroMem (EmptyPassword, sizeof (EmptyPassword));
Status = OemSvcSetSystemPasswords (PasswordType, sizeof (EmptyPassword), EmptyPassword);
if (Status == EFI_MEDIA_CHANGED) {
Status = EFI_SUCCESS;
}
//
// Re-init security item
//
Status = SecurityDataInit (FALSE);
return Status;
}
/**
Check admin password.
@param Password A pointer to the password buffer.
@retval EFI_SUCCESS This function execute successfully.
@retval EFI_ACCESS_DENIED WMI input admin password is invalid.
@retval Others An unexpected error occurred.
**/
EFI_STATUS
WmiCheckAdminPassword (
CHAR8 *Password,
CHAR8 *PasswordEncodingStr,
CHAR8 *PasswordLanguageStr
)
{
EFI_STATUS Status;
CHAR8 *NewPassword;
UINT8 *EncodeAdminPassword;
UINT8 *EncodeAdminPasswordTemp;
CHAR8 *PasswordTypeStr = WMI_BIOS_PASSWORD_ADMIN_TYPE;
WMI_PASSWORD_TYPE PasswordType;
WMI_PASSWORD_ENCODING PasswordEncoding;
WMI_PASSWORD_LANGUAGE PasswordLanguage;
//
// Initialization
//
Status = EFI_SUCCESS;
NewPassword = "";
EncodeAdminPassword = NULL;
EncodeAdminPasswordTemp = NULL;
PasswordType = WmiPasswoedMaxType;
PasswordEncoding = WmiPasswoedMaxEncoding;
PasswordLanguage = WmiPasswoedMaxLanguage;
//
// Check WMI password input buffer is valid
//
Status = CheckWmiPasswordInputBuffer (
PasswordTypeStr,
&PasswordType,
Password,
NewPassword,
PasswordEncodingStr,
&PasswordEncoding,
PasswordLanguageStr,
&PasswordLanguage
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Encode password
//
EncodeAdminPasswordTemp = L05SysPasswordPacket (Password, AsciiStrLen (Password));
EncodeAdminPassword = L05SysPasswordEncode (EncodeAdminPasswordTemp, AsciiStrLen (Password));
if (EncodeAdminPassword == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Compare current password with save password
//
Status = WmiCheckPassword (WmiSystemAdminType, EncodeAdminPassword);
if (EFI_ERROR (Status)) {
mPasswordErrorCount++;
Status = EFI_ACCESS_DENIED;
} else {
//
// Clean password error count
//
mPasswordErrorCount = 0;
}
//
// Free resources
//
FreePool (EncodeAdminPassword);
return Status;
}
UINTN
WmiGetNumOfHdd (
VOID
)
{
EFI_STATUS Status;
EFI_HDD_PASSWORD_SERVICE_PROTOCOL *HddPasswordService;
HDD_PASSWORD_HDD_INFO *HddInfoArray;
UINTN NumOfHdd;
HddPasswordService = NULL;
HddInfoArray = NULL;
Status = gSmst->SmmLocateProtocol (
&gEfiHddPasswordServiceProtocolGuid,
NULL,
&HddPasswordService
);
if (EFI_ERROR (Status)) {
return 0;
}
//
// Get HDD info
//
Status = HddPasswordService->GetHddInfo (
HddPasswordService,
&HddInfoArray,
&NumOfHdd
);
if (EFI_ERROR (Status)) {
return 0;
}
return NumOfHdd;
}
/**
This function uses to get HDD password type number.
@param PasswordType HDD master or user password.
@param PasswordTypeStr A pointer to the password type string.
@param HddPasswordTypeNumber A pointer to the HDD password type number.
@retval EFI_SUCCESS This function execute successfully.
@retval Others An unexpected error occurred.
**/
EFI_STATUS
WmiGetHddPasswordTypeNumber (
IN WMI_PASSWORD_TYPE PasswordType,
IN CHAR8 *PasswordTypeStr,
OUT UINT8 *HddPasswordTypeNumber
)
{
EFI_STATUS Status;
UINTN Index;
CHAR8 *HddPasswordTypeNumberStr;
UINTN NumOfHdd;
Status = EFI_INVALID_PARAMETER;
HddPasswordTypeNumberStr = NULL;
if (PasswordTypeStr == NULL || HddPasswordTypeNumber == NULL) {
return EFI_INVALID_PARAMETER;
}
NumOfHdd = WmiGetNumOfHdd ();
*HddPasswordTypeNumber = 0;
for (Index = 0; Index < mWmiPasswordTypeMapListCount; Index++) {
if (PasswordType == mWmiPasswordTypeMap[Index].PasswordType) {
HddPasswordTypeNumberStr = PasswordTypeStr + AsciiStrLen (mWmiPasswordTypeMap[Index].PasswordTypeStr);
while ((*HddPasswordTypeNumberStr >= L'0' && *HddPasswordTypeNumberStr <= L'9')) {
*HddPasswordTypeNumber *= 10;
*HddPasswordTypeNumber += *HddPasswordTypeNumberStr - L'0';
HddPasswordTypeNumberStr++;
}
if (*HddPasswordTypeNumber == 0 || *HddPasswordTypeNumberStr != 0) {
*HddPasswordTypeNumber = 0;
break;
}
Status = EFI_SUCCESS;
break;
}
}
if (*HddPasswordTypeNumber > NumOfHdd) {
*HddPasswordTypeNumber = 0;
Status = EFI_INVALID_PARAMETER;
}
return Status;
}
/**
WMI Set HDD Passwords.
@param PasswordType HDD master or user password.
@param HddPasswordTypeNumber HDD password type number.
@param HddPasswordBuffer A pointer to the HDD current password.
@param HddNewPassword A pointer to the HDD new password.
@retval EFI_SUCCESS This function execute successfully.
@retval Others An unexpected error occurred.
**/
EFI_STATUS
WmiSetHddPasswords (
IN WMI_PASSWORD_TYPE PasswordType,
IN UINT8 HddPasswordTypeNumber,
IN UINT8 *HddCurrentPassword,
IN UINT8 *HddNewPassword
)
{
EFI_STATUS Status;
HDD_PASSWORD_TABLE HddPasswordTable[WmiHddPasswordMaxSection];
UINTN NumberLength;
CHAR16 *VariableName;
UINTN BufferSize;
//
// Initialization
//
VariableName = NULL;
BufferSize = 0;
ZeroMem (HddPasswordTable, sizeof (HddPasswordTable));
//
// Put HDD current password
//
AsciiStrToUnicodeStrS (HddCurrentPassword, HddPasswordTable[WmiHddPasswordCurrentSection].PasswordStr, HDD_PASSWORD_MAX_NUMBER + 1);
HddPasswordTable[WmiHddPasswordCurrentSection].PasswordType = (UINT8) (PasswordType - WmiHddUserType);
//
// Put HDD new password
//
AsciiStrToUnicodeStrS (HddNewPassword, HddPasswordTable[WmiHddPasswordNewSection].PasswordStr, HDD_PASSWORD_MAX_NUMBER + 1);
HddPasswordTable[WmiHddPasswordNewSection].PasswordType = (UINT8) (PasswordType - WmiHddUserType);
//
// Allocate resources
//
L05_GET_NUMBER_LENGTH (HddPasswordTypeNumber, NumberLength);
BufferSize = StrSize (L05_WMI_HDD_PASWORD_DATA_VARIABLE_NAME) + (NumberLength * sizeof (CHAR16));
VariableName = AllocateZeroPool (BufferSize);
if (VariableName == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Set WMI HDD password variable name
//
UnicodeSPrint (VariableName, BufferSize, L"%s%d", L05_WMI_HDD_PASWORD_DATA_VARIABLE_NAME, HddPasswordTypeNumber);
//
// Set WMI HDD password variable
//
Status = mSmmVariable->SmmSetVariable (
VariableName,
&gL05WmiSetupUnderOsSetupVariableGuid,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
(sizeof (HDD_PASSWORD_TABLE) * WmiHddPasswordMaxSection),
(VOID *) HddPasswordTable
);
//
// Free resources
//
FreePool (VariableName);
return Status;
}
/**
WMI Method for Set BIOS password -
Mapping to WMI class : Lenovo_SetBiosPassword
Mapping to ASL method : WMA6
@param None
@retval EFI_SUCCESS This function execute successfully.
@retval EFI_INVALID_PARAMETER Input invalid password format.
@retval EFI_ACCESS_DENIED Input invalid password rule or password is invalid.
@retval Others An unexpected error occurred.
**/
EFI_STATUS
EFIAPI
WmiSetBiosPasswordA6 (
VOID
)
{
EFI_STATUS Status;
CHAR8 *PasswordTypeStr;
WMI_PASSWORD_TYPE PasswordType;
CHAR8 *CurrentPassword;
CHAR8 *NewPassword;
CHAR8 *PasswordEncodingStr;
WMI_PASSWORD_ENCODING PasswordEncoding;
CHAR8 *PasswordLanguageStr;
WMI_PASSWORD_LANGUAGE PasswordLanguage;
UINT8 *EncodeCurrentPassword;
UINT8 *EncodeCurrentPasswordTemp;
UINT8 *EncodeNewPassword;
UINT8 *EncodeNewPasswordTemp;
UINT8 HddPasswordTypeNumber;
//
// Initialization
//
PasswordTypeStr = NULL;
PasswordType = WmiPasswoedMaxType;
CurrentPassword = NULL;
NewPassword = NULL;
PasswordEncodingStr = NULL;
PasswordEncoding = WmiPasswoedMaxEncoding;
PasswordLanguageStr = NULL;
PasswordLanguage = WmiPasswoedMaxLanguage;
EncodeCurrentPassword = NULL;
EncodeCurrentPasswordTemp = NULL;
EncodeNewPassword = NULL;
EncodeNewPasswordTemp = NULL;
mAdminPasswordExist = WmiIsAdminPasswordExist ();
mUserPasswordExist = WmiIsUserPasswordExist ();
mHddPasswordExist = WmiIsHddPasswordExist ();
//
// Analyze WMI set password input buffer
//
Status = AnalyzeWmiSetPasswordInputBuffer (
&PasswordTypeStr,
&CurrentPassword,
&NewPassword,
&PasswordEncodingStr,
&PasswordLanguageStr
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check WMI password input buffer is valid
//
Status = CheckWmiPasswordInputBuffer (
PasswordTypeStr,
&PasswordType,
CurrentPassword,
NewPassword,
PasswordEncodingStr,
&PasswordEncoding,
PasswordLanguageStr,
&PasswordLanguage
);
if (EFI_ERROR (Status)) {
return Status;
}
switch (PasswordType) {
case WmiSystemAdminType:
case WmiSystemUserType:
//
// Encode password
//
EncodeCurrentPasswordTemp = L05SysPasswordPacket (CurrentPassword, AsciiStrLen (CurrentPassword));
EncodeCurrentPassword = L05SysPasswordEncode (EncodeCurrentPasswordTemp, AsciiStrLen (CurrentPassword));
EncodeNewPasswordTemp = L05SysPasswordPacket (NewPassword, AsciiStrLen (NewPassword));
EncodeNewPassword = L05SysPasswordEncode (EncodeNewPasswordTemp, AsciiStrLen (NewPassword));
if (EncodeCurrentPassword == NULL) {
return EFI_OUT_OF_RESOURCES;
}
if (EncodeNewPassword == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Compare current password with old password
//
Status = WmiCheckPassword (PasswordType, EncodeCurrentPassword);
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
mPasswordErrorCount++;
Status = EFI_ACCESS_DENIED;
break;
}
//
// Avoid password don't exist but when current password exist can set new password
//
if ((!(PasswordType ? mUserPasswordExist : mAdminPasswordExist)) && (AsciiStrLen (CurrentPassword) != 0)) {
mPasswordErrorCount++;
Status = EFI_ACCESS_DENIED;
break;
}
//
// [Lenovo China Minimum BIOS Spec Version 1.37]
// When the user password set, there is an additional submenu added.
// Clear user password menu just appeared in the security menu when
// user entered CMOS setup menu with administrator password.
//
if ((PasswordType == WmiSystemUserType) && (AsciiStrLen (NewPassword) == 0)) {
Status = EFI_ACCESS_DENIED;
break;
}
//
// Set new password.
//
if (AsciiStrLen (NewPassword) != 0) {
#ifndef L05_NOTEBOOK_PASSWORD_ENABLE
Status = OemSvcSetSystemPasswords (PasswordType, (EncodeNewPassword[0] + 2), EncodeNewPassword);
#else
Status = OemSvcSetSystemPasswords (PasswordType, SHA256_DIGEST_SIZE, EncodeNewPassword);
#endif
if (Status == EFI_MEDIA_CHANGED) {
Status = EFI_SUCCESS;
}
}
//
// When clear admin password also need clear user password
//
if ((PasswordType == WmiSystemAdminType) && (AsciiStrLen (NewPassword) == 0)) {
Status = ClearSystemPassword (WmiSystemAdminType);
Status = ClearSystemPassword (WmiSystemUserType);
}
//
// Re-init security item
//
Status = SecurityDataInit (FALSE);
break;
case WmiHddUserType:
case WmiHddMasterType:
#ifdef L05_HDD_PASSWORD_ENABLE
//
// Avoid HDD password don't exist but when current password exist can set new password
//
if (!mHddPasswordExist) {
Status = EFI_ACCESS_DENIED;
break;
}
//
// By L05 Spec., User hdd password can not disable hdd password function.
// return EFI_ACCESS_DENIED for L05 only.
//
if ((PasswordType == WmiHddUserType) && (AsciiStrLen (NewPassword) == 0)) {
Status = EFI_ACCESS_DENIED;
break;
}
//
// Get HDD Number
//
Status = WmiGetHddPasswordTypeNumber (PasswordType, PasswordTypeStr, &HddPasswordTypeNumber);
if (EFI_ERROR (Status) || HddPasswordTypeNumber == 0) {
Status = EFI_ACCESS_DENIED;
break;
}
//
// Set HDD password.
//
Status = WmiSetHddPasswords (PasswordType, HddPasswordTypeNumber, CurrentPassword, NewPassword);
break;
#else
Status = EFI_UNSUPPORTED;
break;
#endif
}
if (!EFI_ERROR (Status)) {
//
// [Lenovo BIOS Setup using WMI Deployment Guide - Third Edition (February 2016)]
// Limitations and Notes:
// 1. BIOS settings cannot be changed at the same boot as power-on passwords (POP) and hard disk passwords
// (HDP). If you want to change BIOS settings and POP or HDP, you must reboot the system after changing
// one of them.
//
mPasswordChange = TRUE;
//
// Init password check data
//
mPasswordCheckData.PasswordType = PasswordType;
AsciiStrCpyS (mPasswordCheckData.CurrentPassword, sizeof (mPasswordCheckData.CurrentPassword), CurrentPassword);
AsciiStrCpyS (mPasswordCheckData.NewPassword, sizeof (mPasswordCheckData.NewPassword), NewPassword);
}
//
// Free resources
//
if (EncodeCurrentPassword != NULL) {
FreePool (EncodeCurrentPassword);
}
if (EncodeNewPassword != NULL) {
FreePool (EncodeNewPassword);
}
return Status;
}