/** @file
This driver manages user information and produces user manager protocol.
Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "UserIdentifyManager.h"
//
// Default user name.
//
CHAR16 mUserName[] = L"Administrator";
//
// Points to the user profile database.
//
USER_PROFILE_DB *mUserProfileDb = NULL;
//
// Points to the credential providers found in system.
//
CREDENTIAL_PROVIDER_INFO *mProviderDb = NULL;
//
// Current user shared in multi function.
//
EFI_USER_PROFILE_HANDLE mCurrentUser = NULL;
//
// Flag indicates a user is identified.
//
BOOLEAN mIdentified = FALSE;
USER_MANAGER_CALLBACK_INFO *mCallbackInfo = NULL;
HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath = {
{
{
HARDWARE_DEVICE_PATH,
HW_VENDOR_DP,
{
(UINT8) (sizeof (VENDOR_DEVICE_PATH)),
(UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
}
},
USER_IDENTIFY_MANAGER_GUID
},
{
END_DEVICE_PATH_TYPE,
END_ENTIRE_DEVICE_PATH_SUBTYPE,
{
(UINT8) (END_DEVICE_PATH_LENGTH),
(UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
}
}
};
EFI_USER_MANAGER_PROTOCOL gUserIdentifyManager = {
UserProfileCreate,
UserProfileDelete,
UserProfileGetNext,
UserProfileCurrent,
UserProfileIdentify,
UserProfileFind,
UserProfileNotify,
UserProfileGetInfo,
UserProfileSetInfo,
UserProfileDeleteInfo,
UserProfileGetNextInfo,
};
/**
Find the specified user in the user database.
This function searches the specified user from the beginning of the user database.
And if NextUser is TRUE, return the next User in the user database.
@param[in, out] User On entry, points to the user profile entry to search.
On return, points to the user profile entry or NULL if not found.
@param[in] NextUser If FALSE, find the user in user profile database specifyed by User
If TRUE, find the next user in user profile database specifyed
by User.
@param[out] ProfileIndex A pointer to the index of user profile database that matches the
user specifyed by User.
@retval EFI_NOT_FOUND User was NULL, or User was not found, or the next user was not found.
@retval EFI_SUCCESS User or the next user are found in user profile database
**/
EFI_STATUS
FindUserProfile (
IN OUT USER_PROFILE_ENTRY **User,
IN BOOLEAN NextUser,
OUT UINTN *ProfileIndex OPTIONAL
)
{
UINTN Index;
//
// Check parameters
//
if ((mUserProfileDb == NULL) || (User == NULL)) {
return EFI_NOT_FOUND;
}
//
// Check whether the user profile is in the user profile database.
//
for (Index = 0; Index < mUserProfileDb->UserProfileNum; Index++) {
if (mUserProfileDb->UserProfile[Index] == *User) {
if (ProfileIndex != NULL) {
*ProfileIndex = Index;
}
break;
}
}
if (NextUser) {
//
// Find the next user profile.
//
Index++;
if (Index < mUserProfileDb->UserProfileNum) {
*User = mUserProfileDb->UserProfile[Index];
} else if (Index == mUserProfileDb->UserProfileNum) {
*User = NULL;
return EFI_NOT_FOUND;
} else {
if ((mUserProfileDb->UserProfileNum > 0) && (*User == NULL)) {
*User = mUserProfileDb->UserProfile[0];
} else {
*User = NULL;
return EFI_NOT_FOUND;
}
}
} else if (Index == mUserProfileDb->UserProfileNum) {
return EFI_NOT_FOUND;
}
return EFI_SUCCESS;
}
/**
Find the specified user information record in the specified User profile.
This function searches the specified user information record from the beginning of the user
profile. And if NextInfo is TRUE, return the next info in the user profile.
@param[in] User Points to the user profile entry.
@param[in, out] Info On entry, points to the user information record or NULL to start
searching with the first user information record.
On return, points to the user information record or NULL if not found.
@param[in] NextInfo If FALSE, find the user information record in profile specifyed by User.
If TRUE, find the next user information record in profile specifyed
by User.
@param[out] Offset A pointer to the offset of the information record in the user profile.
@retval EFI_INVALID_PARAMETER Info is NULL
@retval EFI_NOT_FOUND Info was not found, or the next Info was not found.
@retval EFI_SUCCESS Info or the next info are found in user profile.
**/
EFI_STATUS
FindUserInfo (
IN USER_PROFILE_ENTRY * User,
IN OUT EFI_USER_INFO **Info,
IN BOOLEAN NextInfo,
OUT UINTN *Offset OPTIONAL
)
{
EFI_STATUS Status;
EFI_USER_INFO *UserInfo;
UINTN InfoLen;
if (Info == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Check user profile entry
//
Status = FindUserProfile (&User, FALSE, NULL);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Find user information in the specified user record.
//
InfoLen = 0;
while (InfoLen < User->UserProfileSize) {
UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + InfoLen);
if (UserInfo == *Info) {
if (Offset != NULL) {
*Offset = InfoLen;
}
break;
}
InfoLen += ALIGN_VARIABLE (UserInfo->InfoSize);
}
//
// Check whether to find the next user information.
//
if (NextInfo) {
if (InfoLen < User->UserProfileSize) {
UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + InfoLen);
InfoLen += ALIGN_VARIABLE (UserInfo->InfoSize);
if (InfoLen < User->UserProfileSize) {
*Info = (EFI_USER_INFO *) (User->ProfileInfo + InfoLen);
if (Offset != NULL) {
*Offset = InfoLen;
}
} else if (InfoLen == User->UserProfileSize) {
*Info = NULL;
return EFI_NOT_FOUND;
}
} else {
if (*Info == NULL) {
*Info = (EFI_USER_INFO *) User->ProfileInfo;
if (Offset != NULL) {
*Offset = 0;
}
} else {
*Info = NULL;
return EFI_NOT_FOUND;
}
}
} else if (InfoLen == User->UserProfileSize) {
return EFI_NOT_FOUND;
}
return EFI_SUCCESS;
}
/**
Find a user infomation record by the information record type.
This function searches all user information records of User. The search starts with the
user information record following Info and continues until either the information is found
or there are no more user infomation record.
A match occurs when a Info.InfoType field matches the user information record type.
@param[in] User Points to the user profile record to search.
@param[in, out] Info On entry, points to the user information record or NULL to start
searching with the first user information record.
On return, points to the user information record or NULL if not found.
@param[in] InfoType The infomation type to be searched.
@retval EFI_SUCCESS User information was found. Info points to the user information record.
@retval EFI_NOT_FOUND User information was not found.
@retval EFI_INVALID_PARAMETER User is NULL or Info is NULL.
**/
EFI_STATUS
FindUserInfoByType (
IN USER_PROFILE_ENTRY *User,
IN OUT EFI_USER_INFO **Info,
IN UINT8 InfoType
)
{
EFI_STATUS Status;
EFI_USER_INFO *UserInfo;
UINTN InfoLen;
if (Info == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Check whether the user has the specified user information.
//
InfoLen = 0;
if (*Info == NULL) {
Status = FindUserProfile (&User, FALSE, NULL);
} else {
Status = FindUserInfo (User, Info, TRUE, &InfoLen);
}
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
while (InfoLen < User->UserProfileSize) {
UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + InfoLen);
if (UserInfo->InfoType == InfoType) {
if (UserInfo != *Info) {
*Info = UserInfo;
return EFI_SUCCESS;
}
}
InfoLen += ALIGN_VARIABLE (UserInfo->InfoSize);
}
*Info = NULL;
return EFI_NOT_FOUND;
}
/**
Find a user using a user information record.
This function searches all user profiles for the specified user information record. The
search starts with the user information record handle following UserInfo and continues
until either the information is found or there are no more user profiles.
A match occurs when the Info.InfoType field matches the user information record type and the
user information record data matches the portion of Info passed the EFI_USER_INFO header.
@param[in, out] User On entry, points to the previously returned user profile record,
or NULL to start searching with the first user profile.
On return, points to the user profile entry, or NULL if not found.
@param[in, out] UserInfo On entry, points to the previously returned user information record,
or NULL to start searching with the first.
On return, points to the user information record, or NULL if not found.
@param[in] Info Points to the buffer containing the user information to be compared
to the user information record.
@param[in] InfoSize The size of Info, in bytes. Same as Info->InfoSize.
@retval EFI_SUCCESS User information was found. User points to the user profile record,
and UserInfo points to the user information record.
@retval EFI_NOT_FOUND User information was not found.
@retval EFI_INVALID_PARAMETER User is NULL; Info is NULL; or, InfoSize is too small.
**/
EFI_STATUS
FindUserProfileByInfo (
IN OUT USER_PROFILE_ENTRY **User,
IN OUT EFI_USER_INFO **UserInfo, OPTIONAL
IN EFI_USER_INFO *Info,
IN UINTN InfoSize
)
{
EFI_STATUS Status;
EFI_USER_INFO *InfoEntry;
if ((User == NULL) || (Info == NULL)) {
return EFI_INVALID_PARAMETER;
}
if (InfoSize < sizeof (EFI_USER_INFO)) {
return EFI_INVALID_PARAMETER;
}
if (UserInfo != NULL) {
InfoEntry = *UserInfo;
} else {
InfoEntry = NULL;
}
//
// Find user profile according to information.
//
if (*User == NULL) {
*User = mUserProfileDb->UserProfile[0];
}
//
// Check user profile handle.
//
Status = FindUserProfile (User, FALSE, NULL);
while (!EFI_ERROR (Status)) {
//
// Find the user information in a user profile.
//
while (TRUE) {
Status = FindUserInfoByType (*User, &InfoEntry, Info->InfoType);
if (EFI_ERROR (Status)) {
break;
}
if (InfoSize == Info->InfoSize) {
if (CompareMem ((UINT8 *) (InfoEntry + 1), (UINT8 *) (Info + 1), InfoSize - sizeof (EFI_USER_INFO)) == 0) {
//
// Found the infomation record.
//
if (UserInfo != NULL) {
*UserInfo = InfoEntry;
}
return EFI_SUCCESS;
}
}
}
//
// Get next user profile.
//
InfoEntry = NULL;
Status = FindUserProfile (User, TRUE, NULL);
}
return EFI_NOT_FOUND;
}
/**
Check whether the access policy is valid.
@param[in] PolicyInfo Point to the access policy.
@param[in] InfoLen The policy length.
@retval TRUE The policy is a valid access policy.
@retval FALSE The access policy is not a valid access policy.
**/
BOOLEAN
CheckAccessPolicy (
IN UINT8 *PolicyInfo,
IN UINTN InfoLen
)
{
UINTN TotalLen;
UINTN ValueLen;
UINTN OffSet;
EFI_USER_INFO_ACCESS_CONTROL Access;
EFI_DEVICE_PATH_PROTOCOL *Path;
UINTN PathSize;
TotalLen = 0;
while (TotalLen < InfoLen) {
//
// Check access policy according to type.
//
CopyMem (&Access, PolicyInfo + TotalLen, sizeof (Access));
ValueLen = Access.Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL);
switch (Access.Type) {
case EFI_USER_INFO_ACCESS_FORBID_LOAD:
case EFI_USER_INFO_ACCESS_PERMIT_LOAD:
case EFI_USER_INFO_ACCESS_FORBID_CONNECT:
case EFI_USER_INFO_ACCESS_PERMIT_CONNECT:
OffSet = 0;
while (OffSet < ValueLen) {
Path = (EFI_DEVICE_PATH_PROTOCOL *) (PolicyInfo + TotalLen + sizeof (Access) + OffSet);
PathSize = GetDevicePathSize (Path);
OffSet += PathSize;
}
if (OffSet != ValueLen) {
return FALSE;
}
break;
case EFI_USER_INFO_ACCESS_SETUP:
if (ValueLen % sizeof (EFI_GUID) != 0) {
return FALSE;
}
break;
case EFI_USER_INFO_ACCESS_BOOT_ORDER:
if (ValueLen % sizeof (EFI_USER_INFO_ACCESS_BOOT_ORDER_HDR) != 0) {
return FALSE;
}
break;
case EFI_USER_INFO_ACCESS_ENROLL_SELF:
case EFI_USER_INFO_ACCESS_ENROLL_OTHERS:
case EFI_USER_INFO_ACCESS_MANAGE:
if (ValueLen != 0) {
return FALSE;
}
break;
default:
return FALSE;
break;
}
TotalLen += Access.Size;
}
if (TotalLen != InfoLen) {
return FALSE;
}
return TRUE;
}
/**
Check whether the identity policy is valid.
@param[in] PolicyInfo Point to the identity policy.
@param[in] InfoLen The policy length.
@retval TRUE The policy is a valid identity policy.
@retval FALSE The access policy is not a valid identity policy.
**/
BOOLEAN
CheckIdentityPolicy (
IN UINT8 *PolicyInfo,
IN UINTN InfoLen
)
{
UINTN TotalLen;
UINTN ValueLen;
EFI_USER_INFO_IDENTITY_POLICY *Identity;
TotalLen = 0;
//
// Check each part of policy expression.
//
while (TotalLen < InfoLen) {
//
// Check access polisy according to type.
//
Identity = (EFI_USER_INFO_IDENTITY_POLICY *) (PolicyInfo + TotalLen);
ValueLen = Identity->Length - sizeof (EFI_USER_INFO_IDENTITY_POLICY);
switch (Identity->Type) {
//
// Check False option.
//
case EFI_USER_INFO_IDENTITY_FALSE:
if (ValueLen != 0) {
return FALSE;
}
break;
//
// Check True option.
//
case EFI_USER_INFO_IDENTITY_TRUE:
if (ValueLen != 0) {
return FALSE;
}
break;
//
// Check negative operation.
//
case EFI_USER_INFO_IDENTITY_NOT:
if (ValueLen != 0) {
return FALSE;
}
break;
//
// Check and operation.
//
case EFI_USER_INFO_IDENTITY_AND:
if (ValueLen != 0) {
return FALSE;
}
break;
//
// Check or operation.
//
case EFI_USER_INFO_IDENTITY_OR:
if (ValueLen != 0) {
return FALSE;
}
break;
//
// Check credential provider by type.
//
case EFI_USER_INFO_IDENTITY_CREDENTIAL_TYPE:
if (ValueLen != sizeof (EFI_GUID)) {
return FALSE;
}
break;
//
// Check credential provider by ID.
//
case EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER:
if (ValueLen != sizeof (EFI_GUID)) {
return FALSE;
}
break;
default:
return FALSE;
break;
}
TotalLen += Identity->Length;
}
if (TotalLen != InfoLen) {
return FALSE;
}
return TRUE;
}
/**
Check whether the user information is a valid user information record.
@param[in] Info points to the user information.
@retval TRUE The info is a valid user information record.
@retval FALSE The info is not a valid user information record.
**/
BOOLEAN
CheckUserInfo (
IN CONST EFI_USER_INFO *Info
)
{
UINTN InfoLen;
if (Info == NULL) {
return FALSE;
}
//
// Check user information according to information type.
//
InfoLen = Info->InfoSize - sizeof (EFI_USER_INFO);
switch (Info->InfoType) {
case EFI_USER_INFO_EMPTY_RECORD:
if (InfoLen != 0) {
return FALSE;
}
break;
case EFI_USER_INFO_NAME_RECORD:
case EFI_USER_INFO_CREDENTIAL_TYPE_NAME_RECORD:
case EFI_USER_INFO_CREDENTIAL_PROVIDER_NAME_RECORD:
break;
case EFI_USER_INFO_CREATE_DATE_RECORD:
case EFI_USER_INFO_USAGE_DATE_RECORD:
if (InfoLen != sizeof (EFI_TIME)) {
return FALSE;
}
break;
case EFI_USER_INFO_USAGE_COUNT_RECORD:
if (InfoLen != sizeof (UINT64)) {
return FALSE;
}
break;
case EFI_USER_INFO_IDENTIFIER_RECORD:
if (InfoLen != 16) {
return FALSE;
}
break;
case EFI_USER_INFO_CREDENTIAL_TYPE_RECORD:
case EFI_USER_INFO_CREDENTIAL_PROVIDER_RECORD:
case EFI_USER_INFO_GUID_RECORD:
if (InfoLen != sizeof (EFI_GUID)) {
return FALSE;
}
break;
case EFI_USER_INFO_PKCS11_RECORD:
case EFI_USER_INFO_CBEFF_RECORD:
break;
case EFI_USER_INFO_FAR_RECORD:
case EFI_USER_INFO_RETRY_RECORD:
if (InfoLen != 1) {
return FALSE;
}
break;
case EFI_USER_INFO_ACCESS_POLICY_RECORD:
if(!CheckAccessPolicy ((UINT8 *) (Info + 1), InfoLen)) {
return FALSE;
}
break;
case EFI_USER_INFO_IDENTITY_POLICY_RECORD:
if (!CheckIdentityPolicy ((UINT8 *) (Info + 1), InfoLen)) {
return FALSE;
}
break;
default:
return FALSE;
break;
}
return TRUE;
}
/**
Check the user profile data format to be added.
@param[in] UserProfileInfo Points to the user profile data.
@param[in] UserProfileSize The length of user profile data.
@retval TRUE It is a valid user profile.
@retval FALSE It is not a valid user profile.
**/
BOOLEAN
CheckProfileInfo (
IN UINT8 *UserProfileInfo,
IN UINTN UserProfileSize
)
{
UINTN ChkLen;
EFI_USER_INFO *Info;
if (UserProfileInfo == NULL) {
return FALSE;
}
//
// Check user profile information length.
//
ChkLen = 0;
while (ChkLen < UserProfileSize) {
Info = (EFI_USER_INFO *) (UserProfileInfo + ChkLen);
//
// Check user information format.
//
if (!CheckUserInfo (Info)) {
return FALSE;
}
ChkLen += ALIGN_VARIABLE (Info->InfoSize);
}
if (ChkLen != UserProfileSize) {
return FALSE;
}
return TRUE;
}
/**
Find the specified RightType in current user profile.
@param[in] RightType Could be EFI_USER_INFO_ACCESS_MANAGE,
EFI_USER_INFO_ACCESS_ENROLL_OTHERS or
EFI_USER_INFO_ACCESS_ENROLL_SELF.
@retval TRUE Find the specified RightType in current user profile.
@retval FALSE Can't find the right in the profile.
**/
BOOLEAN
CheckCurrentUserAccessRight (
IN UINT32 RightType
)
{
EFI_STATUS Status;
EFI_USER_INFO *Info;
UINTN TotalLen;
UINTN CheckLen;
EFI_USER_INFO_ACCESS_CONTROL Access;
//
// Get user access right information.
//
Info = NULL;
Status = FindUserInfoByType (
(USER_PROFILE_ENTRY *) mCurrentUser,
&Info,
EFI_USER_INFO_ACCESS_POLICY_RECORD
);
if (EFI_ERROR (Status)) {
return FALSE;
}
ASSERT (Info != NULL);
TotalLen = Info->InfoSize - sizeof (EFI_USER_INFO);
CheckLen = 0;
while (CheckLen < TotalLen) {
//
// Check right according to access type.
//
CopyMem (&Access, (UINT8 *) (Info + 1) + CheckLen, sizeof (Access));
if (Access.Type == RightType) {
return TRUE;;
}
CheckLen += Access.Size;
}
return FALSE;
}
/**
Create a unique user identifier.
@param[out] Identifier This points to the identifier.
**/
VOID
GenerateIdentifier (
OUT UINT8 *Identifier
)
{
EFI_TIME Time;
UINT64 MonotonicCount;
UINT32 *MonotonicPointer;
UINTN Index;
//
// Create a unique user identifier.
//
gRT->GetTime (&Time, NULL);
CopyMem (Identifier, &Time, sizeof (EFI_TIME));
//
// Remove zeros.
//
for (Index = 0; Index < sizeof (EFI_TIME); Index++) {
if (Identifier[Index] == 0) {
Identifier[Index] = 0x5a;
}
}
MonotonicPointer = (UINT32 *) Identifier;
gBS->GetNextMonotonicCount (&MonotonicCount);
MonotonicPointer[0] += (UINT32) MonotonicCount;
MonotonicPointer[1] += (UINT32) MonotonicCount;
MonotonicPointer[2] += (UINT32) MonotonicCount;
MonotonicPointer[3] += (UINT32) MonotonicCount;
}
/**
Generate unique user ID.
@param[out] UserId Points to the user identifer.
**/
VOID
GenerateUserId (
OUT UINT8 *UserId
)
{
EFI_STATUS Status;
USER_PROFILE_ENTRY *UserProfile;
EFI_USER_INFO *UserInfo;
UINTN Index;
//
// Generate unique user ID
//
while (TRUE) {
GenerateIdentifier (UserId);
//
// Check whether it's unique in user profile database.
//
if (mUserProfileDb == NULL) {
return ;
}
for (Index = 0; Index < mUserProfileDb->UserProfileNum; Index++) {
UserProfile = (USER_PROFILE_ENTRY *) (mUserProfileDb->UserProfile[Index]);
UserInfo = NULL;
Status = FindUserInfoByType (UserProfile, &UserInfo, EFI_USER_INFO_IDENTIFIER_RECORD);
if (EFI_ERROR (Status)) {
continue;
}
if (CompareMem ((UINT8 *) (UserInfo + 1), UserId, sizeof (EFI_USER_INFO_IDENTIFIER)) == 0) {
break;
}
}
if (Index == mUserProfileDb->UserProfileNum) {
return ;
}
}
}
/**
Expand user profile database.
@retval TRUE Success to expand user profile database.
@retval FALSE Fail to expand user profile database.
**/
BOOLEAN
ExpandUsermUserProfileDb (
VOID
)
{
UINTN MaxNum;
USER_PROFILE_DB *NewDataBase;
//
// Create new user profile database.
//
if (mUserProfileDb == NULL) {
MaxNum = USER_NUMBER_INC;
} else {
MaxNum = mUserProfileDb->MaxProfileNum + USER_NUMBER_INC;
}
NewDataBase = AllocateZeroPool (
sizeof (USER_PROFILE_DB) - sizeof (EFI_USER_PROFILE_HANDLE) +
MaxNum * sizeof (EFI_USER_PROFILE_HANDLE)
);
if (NewDataBase == NULL) {
return FALSE;
}
NewDataBase->MaxProfileNum = MaxNum;
//
// Copy old user profile database value
//
if (mUserProfileDb == NULL) {
NewDataBase->UserProfileNum = 0;
} else {
NewDataBase->UserProfileNum = mUserProfileDb->UserProfileNum;
CopyMem (
NewDataBase->UserProfile,
mUserProfileDb->UserProfile,
NewDataBase->UserProfileNum * sizeof (EFI_USER_PROFILE_HANDLE)
);
FreePool (mUserProfileDb);
}
mUserProfileDb = NewDataBase;
return TRUE;
}
/**
Expand user profile
@param[in] User Points to user profile.
@param[in] ExpandSize The size of user profile.
@retval TRUE Success to expand user profile size.
@retval FALSE Fail to expand user profile size.
**/
BOOLEAN
ExpandUserProfile (
IN USER_PROFILE_ENTRY *User,
IN UINTN ExpandSize
)
{
UINT8 *Info;
UINTN InfoSizeInc;
//
// Allocate new memory.
//
InfoSizeInc = 128;
User->MaxProfileSize += ((ExpandSize + InfoSizeInc - 1) / InfoSizeInc) * InfoSizeInc;
Info = AllocateZeroPool (User->MaxProfileSize);
if (Info == NULL) {
return FALSE;
}
//
// Copy exist information.
//
if (User->UserProfileSize > 0) {
CopyMem (Info, User->ProfileInfo, User->UserProfileSize);
FreePool (User->ProfileInfo);
}
User->ProfileInfo = Info;
return TRUE;
}
/**
Save the user profile to non-volatile memory, or delete it from non-volatile memory.
@param[in] User Point to the user profile
@param[in] Delete If TRUE, delete the found user profile.
If FALSE, save the user profile.
@retval EFI_SUCCESS Save or delete user profile successfully.
@retval Others Fail to change the profile.
**/
EFI_STATUS
SaveNvUserProfile (
IN USER_PROFILE_ENTRY *User,
IN BOOLEAN Delete
)
{
EFI_STATUS Status;
//
// Check user profile entry.
//
Status = FindUserProfile (&User, FALSE, NULL);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Save the user profile to non-volatile memory.
//
Status = gRT->SetVariable (
User->UserVarName,
&gUserIdentifyManagerGuid,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
Delete ? 0 : User->UserProfileSize,
User->ProfileInfo
);
return Status;
}
/**
Add one new user info into the user's profile.
@param[in] User point to the user profile
@param[in] Info Points to the user information payload.
@param[in] InfoSize The size of the user information payload, in bytes.
@param[out] UserInfo Point to the new info in user profile
@param[in] Save If TRUE, save the profile to NV flash.
If FALSE, don't need to save the profile to NV flash.
@retval EFI_SUCCESS Add user info to user profile successfully.
@retval Others Fail to add user info to user profile.
**/
EFI_STATUS
AddUserInfo (
IN USER_PROFILE_ENTRY *User,
IN UINT8 *Info,
IN UINTN InfoSize,
OUT EFI_USER_INFO **UserInfo, OPTIONAL
IN BOOLEAN Save
)
{
EFI_STATUS Status;
if ((Info == NULL) || (User == NULL)) {
return EFI_INVALID_PARAMETER;
}
//
// Check user profile handle.
//
Status = FindUserProfile (&User, FALSE, NULL);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check user information memory size.
//
if (User->MaxProfileSize - User->UserProfileSize < ALIGN_VARIABLE (InfoSize)) {
if (!ExpandUserProfile (User, ALIGN_VARIABLE (InfoSize))) {
return EFI_OUT_OF_RESOURCES;
}
}
//
// Add new user information.
//
CopyMem (User->ProfileInfo + User->UserProfileSize, Info, InfoSize);
if (UserInfo != NULL) {
*UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + User->UserProfileSize);
}
User->UserProfileSize += ALIGN_VARIABLE (InfoSize);
//
// Save user profile information.
//
if (Save) {
Status = SaveNvUserProfile (User, FALSE);
}
return Status;
}
/**
Get the user info from the specified user info handle.
@param[in] User Point to the user profile.
@param[in] UserInfo Point to the user information record to get.
@param[out] Info On entry, points to a buffer of at least *InfoSize bytes.
On exit, holds the user information.
@param[in, out] InfoSize On entry, points to the size of Info.
On return, points to the size of the user information.
@param[in] ChkRight If TRUE, check the user info attribute.
If FALSE, don't check the user info attribute.
@retval EFI_ACCESS_DENIED The information cannot be accessed by the current user.
@retval EFI_INVALID_PARAMETER InfoSize is NULL or UserInfo is NULL.
@retval EFI_BUFFER_TOO_SMALL The number of bytes specified by *InfoSize is too small to hold the
returned data. The actual size required is returned in *InfoSize.
@retval EFI_SUCCESS Information returned successfully.
**/
EFI_STATUS
GetUserInfo (
IN USER_PROFILE_ENTRY *User,
IN EFI_USER_INFO *UserInfo,
OUT EFI_USER_INFO *Info,
IN OUT UINTN *InfoSize,
IN BOOLEAN ChkRight
)
{
EFI_STATUS Status;
if ((InfoSize == NULL) || (UserInfo == NULL)) {
return EFI_INVALID_PARAMETER;
}
if ((*InfoSize != 0) && (Info == NULL)) {
return EFI_INVALID_PARAMETER;
}
//
// Find the user information to get.
//
Status = FindUserInfo (User, &UserInfo, FALSE, NULL);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check information attributes.
//
if (ChkRight) {
switch (UserInfo->InfoAttribs & EFI_USER_INFO_ACCESS) {
case EFI_USER_INFO_PRIVATE:
case EFI_USER_INFO_PROTECTED:
if (User != mCurrentUser) {
return EFI_ACCESS_DENIED;
}
break;
case EFI_USER_INFO_PUBLIC:
break;
default:
return EFI_INVALID_PARAMETER;
break;
}
}
//
// Get user information.
//
if (UserInfo->InfoSize > *InfoSize) {
*InfoSize = UserInfo->InfoSize;
return EFI_BUFFER_TOO_SMALL;
}
*InfoSize = UserInfo->InfoSize;
if (Info != NULL) {
CopyMem (Info, UserInfo, *InfoSize);
}
return EFI_SUCCESS;
}
/**
Delete the specified user information from user profile.
@param[in] User Point to the user profile.
@param[in] Info Point to the user information record to delete.
@param[in] Save If TRUE, save the profile to NV flash.
If FALSE, don't need to save the profile to NV flash.
@retval EFI_SUCCESS Delete user info from user profile successfully.
@retval Others Fail to delete user info from user profile.
**/
EFI_STATUS
DelUserInfo (
IN USER_PROFILE_ENTRY *User,
IN EFI_USER_INFO *Info,
IN BOOLEAN Save
)
{
EFI_STATUS Status;
UINTN Offset;
UINTN NextOffset;
//
// Check user information handle.
//
Status = FindUserInfo (User, &Info, FALSE, &Offset);
if (EFI_ERROR (Status)) {
return Status;
}
if (Info->InfoType == EFI_USER_INFO_IDENTIFIER_RECORD) {
return EFI_ACCESS_DENIED;
}
//
// Delete the specified user information.
//
NextOffset = Offset + ALIGN_VARIABLE (Info->InfoSize);
User->UserProfileSize -= ALIGN_VARIABLE (Info->InfoSize);
if (Offset < User->UserProfileSize) {
CopyMem (User->ProfileInfo + Offset, User->ProfileInfo + NextOffset, User->UserProfileSize - Offset);
}
if (Save) {
Status = SaveNvUserProfile (User, FALSE);
}
return Status;
}
/**
Add or update user information.
@param[in] User Point to the user profile.
@param[in, out] UserInfo On entry, points to the user information to modify,
or NULL to add a new UserInfo.
On return, points to the modified user information.
@param[in] Info Points to the new user information.
@param[in] InfoSize The size of Info,in bytes.
@retval EFI_INVALID_PARAMETER UserInfo is NULL or Info is NULL.
@retval EFI_ACCESS_DENIED The record is exclusive.
@retval EFI_SUCCESS User information was successfully changed/added.
**/
EFI_STATUS
ModifyUserInfo (
IN USER_PROFILE_ENTRY *User,
IN OUT EFI_USER_INFO **UserInfo,
IN CONST EFI_USER_INFO *Info,
IN UINTN InfoSize
)
{
EFI_STATUS Status;
UINTN PayloadLen;
EFI_USER_INFO *OldInfo;
if ((UserInfo == NULL) || (Info == NULL)) {
return EFI_INVALID_PARAMETER;
}
if (InfoSize < sizeof (EFI_USER_INFO) || InfoSize != Info->InfoSize) {
return EFI_INVALID_PARAMETER;
}
//
// Check user information.
//
if (Info->InfoType == EFI_USER_INFO_IDENTIFIER_RECORD) {
return EFI_ACCESS_DENIED;
}
if (!CheckUserInfo (Info)) {
return EFI_INVALID_PARAMETER;
}
if (*UserInfo == NULL) {
//
// Add new user information.
//
OldInfo = NULL;
do {
Status = FindUserInfoByType (User, &OldInfo, Info->InfoType);
if (EFI_ERROR (Status)) {
break;
}
ASSERT (OldInfo != NULL);
if (((OldInfo->InfoAttribs & EFI_USER_INFO_EXCLUSIVE) != 0) ||
((Info->InfoAttribs & EFI_USER_INFO_EXCLUSIVE) != 0)) {
//
// Same type can not co-exist for exclusive information.
//
return EFI_ACCESS_DENIED;
}
//
// Check whether it exists in DB.
//
if (Info->InfoSize != OldInfo->InfoSize) {
continue;
}
if (!CompareGuid (&OldInfo->Credential, &Info->Credential)) {
continue;
}
PayloadLen = Info->InfoSize - sizeof (EFI_USER_INFO);
if (PayloadLen == 0) {
continue;
}
if (CompareMem ((UINT8 *)(OldInfo + 1), (UINT8 *)(Info + 1), PayloadLen) != 0) {
continue;
}
//
// Yes. The new info is as same as the one in profile.
//
return EFI_SUCCESS;
} while (!EFI_ERROR (Status));
Status = AddUserInfo (User, (UINT8 *) Info, InfoSize, UserInfo, TRUE);
return Status;
}
//
// Modify existing user information.
//
OldInfo = *UserInfo;
if (OldInfo->InfoType != Info->InfoType) {
return EFI_INVALID_PARAMETER;
}
if (((Info->InfoAttribs & EFI_USER_INFO_EXCLUSIVE) != 0) &&
(OldInfo->InfoAttribs & EFI_USER_INFO_EXCLUSIVE) == 0) {
//
// Try to add exclusive attrib in new info.
// Check whether there is another information with the same type in profile.
//
OldInfo = NULL;
do {
Status = FindUserInfoByType (User, &OldInfo, Info->InfoType);
if (EFI_ERROR (Status)) {
break;
}
if (OldInfo != *UserInfo) {
//
// There is another information with the same type in profile.
// Therefore, can't modify existing user information to add exclusive attribute.
//
return EFI_ACCESS_DENIED;
}
} while (TRUE);
}
Status = DelUserInfo (User, *UserInfo, FALSE);
if (EFI_ERROR (Status)) {
return Status;
}
return AddUserInfo (User, (UINT8 *) Info, InfoSize, UserInfo, TRUE);
}
/**
Delete the user profile from non-volatile memory and database.
@param[in] User Points to the user profile.
@retval EFI_SUCCESS Delete user from the user profile successfully.
@retval Others Fail to delete user from user profile
**/
EFI_STATUS
DelUserProfile (
IN USER_PROFILE_ENTRY *User
)
{
EFI_STATUS Status;
UINTN Index;
//
// Check whether it is in the user profile database.
//
Status = FindUserProfile (&User, FALSE, &Index);
if (EFI_ERROR (Status)) {
return EFI_INVALID_PARAMETER;
}
//
// Check whether it is the current user.
//
if (User == mCurrentUser) {
return EFI_ACCESS_DENIED;
}
//
// Delete user profile from the non-volatile memory.
//
Status = SaveNvUserProfile (mUserProfileDb->UserProfile[mUserProfileDb->UserProfileNum - 1], TRUE);
if (EFI_ERROR (Status)) {
return Status;
}
mUserProfileDb->UserProfileNum--;
//
// Modify user profile database.
//
if (Index != mUserProfileDb->UserProfileNum) {
mUserProfileDb->UserProfile[Index] = mUserProfileDb->UserProfile[mUserProfileDb->UserProfileNum];
CopyMem (
((USER_PROFILE_ENTRY *) mUserProfileDb->UserProfile[Index])->UserVarName,
User->UserVarName,
sizeof (User->UserVarName)
);
Status = SaveNvUserProfile (mUserProfileDb->UserProfile[Index], FALSE);
if (EFI_ERROR (Status)) {
return Status;
}
}
//
// Delete user profile information.
//
if (User->ProfileInfo != NULL) {
FreePool (User->ProfileInfo);
}
FreePool (User);
return EFI_SUCCESS;
}
/**
Add user profile to user profile database.
@param[out] UserProfile Point to the newly added user profile.
@param[in] ProfileSize The size of the user profile.
@param[in] ProfileInfo Point to the user profie data.
@param[in] Save If TRUE, save the new added profile to NV flash.
If FALSE, don't save the profile to NV flash.
@retval EFI_SUCCESS Add user profile to user profile database successfully.
@retval Others Fail to add user profile to user profile database.
**/
EFI_STATUS
AddUserProfile (
OUT USER_PROFILE_ENTRY **UserProfile, OPTIONAL
IN UINTN ProfileSize,
IN UINT8 *ProfileInfo,
IN BOOLEAN Save
)
{
EFI_STATUS Status;
USER_PROFILE_ENTRY *User;
//
// Check the data format to be added.
//
if (!CheckProfileInfo (ProfileInfo, ProfileSize)) {
return EFI_SECURITY_VIOLATION;
}
//
// Create user profile entry.
//
User = AllocateZeroPool (sizeof (USER_PROFILE_ENTRY));
if (User == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Add the entry to the user profile database.
//
if (mUserProfileDb->UserProfileNum == mUserProfileDb->MaxProfileNum) {
if (!ExpandUsermUserProfileDb ()) {
FreePool (User);
return EFI_OUT_OF_RESOURCES;
}
}
UnicodeSPrint (
User->UserVarName,
sizeof (User->UserVarName),
L"User%04x",
mUserProfileDb->UserProfileNum
);
User->UserProfileSize = 0;
User->MaxProfileSize = 0;
User->ProfileInfo = NULL;
mUserProfileDb->UserProfile[mUserProfileDb->UserProfileNum] = (EFI_USER_PROFILE_HANDLE) User;
mUserProfileDb->UserProfileNum++;
//
// Add user profile information.
//
Status = AddUserInfo (User, ProfileInfo, ProfileSize, NULL, Save);
if (EFI_ERROR (Status)) {
DelUserProfile (User);
return Status;
}
//
// Set new user profile handle.
//
if (UserProfile != NULL) {
*UserProfile = User;
}
return EFI_SUCCESS;
}
/**
This function creates a new user profile with only a new user identifier
attached and returns its handle. The user profile is non-volatile, but the
handle User can change across reboots.
@param[out] User Handle of a new user profile.
@retval EFI_SUCCESS User profile was successfully created.
@retval Others Fail to create user profile
**/
EFI_STATUS
CreateUserProfile (
OUT USER_PROFILE_ENTRY **User
)
{
EFI_STATUS Status;
EFI_USER_INFO *UserInfo;
if (User == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Generate user id information.
//
UserInfo = AllocateZeroPool (sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_IDENTIFIER));
if (UserInfo == NULL) {
return EFI_OUT_OF_RESOURCES;
}
UserInfo->InfoType = EFI_USER_INFO_IDENTIFIER_RECORD;
UserInfo->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_IDENTIFIER);
UserInfo->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;
GenerateUserId ((UINT8 *) (UserInfo + 1));
//
// Add user profile to the user profile database.
//
Status = AddUserProfile (User, UserInfo->InfoSize, (UINT8 *) UserInfo, TRUE);
FreePool (UserInfo);
return Status;
}
/**
Add a default user profile to user profile database.
@retval EFI_SUCCESS A default user profile is added successfully.
@retval Others Fail to add a default user profile
**/
EFI_STATUS
AddDefaultUserProfile (
VOID
)
{
EFI_STATUS Status;
USER_PROFILE_ENTRY *User;
EFI_USER_INFO *Info;
EFI_USER_INFO *NewInfo;
EFI_USER_INFO_CREATE_DATE CreateDate;
EFI_USER_INFO_USAGE_COUNT UsageCount;
EFI_USER_INFO_ACCESS_CONTROL *Access;
EFI_USER_INFO_IDENTITY_POLICY *Policy;
//
// Create a user profile.
//
Status = CreateUserProfile (&User);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Allocate a buffer to add all default user information.
//
Info = AllocateZeroPool (sizeof (EFI_USER_INFO) + INFO_PAYLOAD_SIZE);
if (Info == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Add user name.
//
Info->InfoType = EFI_USER_INFO_NAME_RECORD;
Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;
Info->InfoSize = sizeof (EFI_USER_INFO) + sizeof (mUserName);
CopyMem ((UINT8 *) (Info + 1), mUserName, sizeof (mUserName));
NewInfo = NULL;
Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);
if (EFI_ERROR (Status)) {
goto Done;
}
//
// Add user profile create date record.
//
Info->InfoType = EFI_USER_INFO_CREATE_DATE_RECORD;
Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;
Info->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_CREATE_DATE);
Status = gRT->GetTime (&CreateDate, NULL);
if (EFI_ERROR (Status)) {
goto Done;
}
CopyMem ((UINT8 *) (Info + 1), &CreateDate, sizeof (EFI_USER_INFO_CREATE_DATE));
NewInfo = NULL;
Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);
if (EFI_ERROR (Status)) {
goto Done;
}
//
// Add user profile usage count record.
//
Info->InfoType = EFI_USER_INFO_USAGE_COUNT_RECORD;
Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;
Info->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_USAGE_COUNT);
UsageCount = 0;
CopyMem ((UINT8 *) (Info + 1), &UsageCount, sizeof (EFI_USER_INFO_USAGE_COUNT));
NewInfo = NULL;
Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);
if (EFI_ERROR (Status)) {
goto Done;
}
//
// Add user access right.
//
Info->InfoType = EFI_USER_INFO_ACCESS_POLICY_RECORD;
Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;
Access = (EFI_USER_INFO_ACCESS_CONTROL *) (Info + 1);
Access->Type = EFI_USER_INFO_ACCESS_MANAGE;
Access->Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL);
Info->InfoSize = sizeof (EFI_USER_INFO) + Access->Size;
NewInfo = NULL;
Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);
if (EFI_ERROR (Status)) {
goto Done;
}
//
// Add user identity policy.
//
Info->InfoType = EFI_USER_INFO_IDENTITY_POLICY_RECORD;
Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PRIVATE | EFI_USER_INFO_EXCLUSIVE;
Policy = (EFI_USER_INFO_IDENTITY_POLICY *) (Info + 1);
Policy->Type = EFI_USER_INFO_IDENTITY_TRUE;
Policy->Length = sizeof (EFI_USER_INFO_IDENTITY_POLICY);
Info->InfoSize = sizeof (EFI_USER_INFO) + Policy->Length;
NewInfo = NULL;
Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);
Done:
FreePool (Info);
return Status;
}
/**
Publish current user information into EFI System Configuration Table.
By UEFI spec, the User Identity Manager will publish the current user profile
into the EFI System Configuration Table. Currently, only the user identifier and user
name are published.
@retval EFI_SUCCESS Current user information is published successfully.
@retval Others Fail to publish current user information
**/
EFI_STATUS
PublishUserTable (
VOID
)
{
EFI_STATUS Status;
EFI_CONFIGURATION_TABLE *EfiConfigurationTable;
EFI_USER_INFO_TABLE *UserInfoTable;
EFI_USER_INFO *IdInfo;
EFI_USER_INFO *NameInfo;
Status = EfiGetSystemConfigurationTable (
&gEfiUserManagerProtocolGuid,
(VOID **) &EfiConfigurationTable
);
if (!EFI_ERROR (Status)) {
//
// The table existed!
//
return EFI_SUCCESS;
}
//
// Get user ID information.
//
IdInfo = NULL;
Status = FindUserInfoByType (mCurrentUser, &IdInfo, EFI_USER_INFO_IDENTIFIER_RECORD);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get user name information.
//
NameInfo = NULL;
Status = FindUserInfoByType (mCurrentUser, &NameInfo, EFI_USER_INFO_NAME_RECORD);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Allocate a buffer for user information table.
//
UserInfoTable = (EFI_USER_INFO_TABLE *) AllocateRuntimePool (
sizeof (EFI_USER_INFO_TABLE) +
IdInfo->InfoSize +
NameInfo->InfoSize
);
if (UserInfoTable == NULL) {
Status = EFI_OUT_OF_RESOURCES;
return Status;
}
UserInfoTable->Size = sizeof (EFI_USER_INFO_TABLE);
//
// Append the user information to the user info table
//
CopyMem ((UINT8 *) UserInfoTable + UserInfoTable->Size, (UINT8 *) IdInfo, IdInfo->InfoSize);
UserInfoTable->Size += IdInfo->InfoSize;
CopyMem ((UINT8 *) UserInfoTable + UserInfoTable->Size, (UINT8 *) NameInfo, NameInfo->InfoSize);
UserInfoTable->Size += NameInfo->InfoSize;
Status = gBS->InstallConfigurationTable (&gEfiUserManagerProtocolGuid, (VOID *) UserInfoTable);
return Status;
}
/**
Get the user's identity type.
The identify manager only supports the identity policy in which the credential
provider handles are connected by the operator 'AND' or 'OR'.
@param[in] User Handle of a user profile.
@param[out] PolicyType Point to the identity type.
@retval EFI_SUCCESS Get user's identity type successfully.
@retval Others Fail to get user's identity type.
**/
EFI_STATUS
GetIdentifyType (
IN EFI_USER_PROFILE_HANDLE User,
OUT UINT8 *PolicyType
)
{
EFI_STATUS Status;
EFI_USER_INFO *IdentifyInfo;
UINTN TotalLen;
EFI_USER_INFO_IDENTITY_POLICY *Identity;
//
// Get user identify policy information.
//
IdentifyInfo = NULL;
Status = FindUserInfoByType (User, &IdentifyInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);
if (EFI_ERROR (Status)) {
return Status;
}
ASSERT (IdentifyInfo != NULL);
//
// Search the user identify policy according to type.
//
TotalLen = 0;
*PolicyType = EFI_USER_INFO_IDENTITY_FALSE;
while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) {
Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen);
if (Identity->Type == EFI_USER_INFO_IDENTITY_AND) {
*PolicyType = EFI_USER_INFO_IDENTITY_AND;
break;
}
if (Identity->Type == EFI_USER_INFO_IDENTITY_OR) {
*PolicyType = EFI_USER_INFO_IDENTITY_OR;
break;
}
TotalLen += Identity->Length;
}
return EFI_SUCCESS;
}
/**
Identify the User by the specfied provider.
@param[in] User Handle of a user profile.
@param[in] Provider Points to the identifier of credential provider.
@retval EFI_INVALID_PARAMETER Provider is NULL.
@retval EFI_NOT_FOUND Fail to identify the specified user.
@retval EFI_SUCCESS User is identified successfully.
**/
EFI_STATUS
IdentifyByProviderId (
IN EFI_USER_PROFILE_HANDLE User,
IN EFI_GUID *Provider
)
{
EFI_STATUS Status;
EFI_USER_INFO_IDENTIFIER UserId;
UINTN Index;
EFI_CREDENTIAL_LOGON_FLAGS AutoLogon;
EFI_HII_HANDLE HiiHandle;
EFI_GUID FormSetId;
EFI_FORM_ID FormId;
EFI_USER_CREDENTIAL2_PROTOCOL *UserCredential;
if (Provider == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Check the user ID identified by the specified credential provider.
//
for (Index = 0; Index < mProviderDb->Count; Index++) {
//
// Check credential provider class.
//
UserCredential = mProviderDb->Provider[Index];
if (CompareGuid (&UserCredential->Identifier, Provider)) {
Status = UserCredential->Select (UserCredential, &AutoLogon);
if (EFI_ERROR (Status)) {
return Status;
}
if ((AutoLogon & EFI_CREDENTIAL_LOGON_FLAG_AUTO) == 0) {
//
// Get credential provider form.
//
Status = UserCredential->Form (
UserCredential,
&HiiHandle,
&FormSetId,
&FormId
);
if (!EFI_ERROR (Status)) {
//
// Send form to get user input.
//
Status = mCallbackInfo->FormBrowser2->SendForm (
mCallbackInfo->FormBrowser2,
&HiiHandle,
1,
&FormSetId,
FormId,
NULL,
NULL
);
if (EFI_ERROR (Status)) {
return Status;
}
}
}
Status = UserCredential->User (UserCredential, User, &UserId);
if (EFI_ERROR (Status)) {
return Status;
}
Status = UserCredential->Deselect (UserCredential);
if (EFI_ERROR (Status)) {
return Status;
}
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}
/**
Update user information when user is logon on successfully.
@param[in] User Points to user profile.
@retval EFI_SUCCESS Update user information successfully.
@retval Others Fail to update user information.
**/
EFI_STATUS
UpdateUserInfo (
IN USER_PROFILE_ENTRY *User
)
{
EFI_STATUS Status;
EFI_USER_INFO *Info;
EFI_USER_INFO *NewInfo;
EFI_USER_INFO_CREATE_DATE Date;
EFI_USER_INFO_USAGE_COUNT UsageCount;
UINTN InfoLen;
//
// Allocate a buffer to update user's date record and usage record.
//
InfoLen = MAX (sizeof (EFI_USER_INFO_CREATE_DATE), sizeof (EFI_USER_INFO_USAGE_COUNT));
Info = AllocateZeroPool (sizeof (EFI_USER_INFO) + InfoLen);
if (Info == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Check create date record.
//
NewInfo = NULL;
Status = FindUserInfoByType (User, &NewInfo, EFI_USER_INFO_CREATE_DATE_RECORD);
if (Status == EFI_NOT_FOUND) {
Info->InfoType = EFI_USER_INFO_CREATE_DATE_RECORD;
Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;
Info->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_CREATE_DATE);
Status = gRT->GetTime (&Date, NULL);
if (EFI_ERROR (Status)) {
FreePool (Info);
return Status;
}
CopyMem ((UINT8 *) (Info + 1), &Date, sizeof (EFI_USER_INFO_CREATE_DATE));
NewInfo = NULL;
Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);
if (EFI_ERROR (Status)) {
FreePool (Info);
return Status;
}
}
//
// Update usage date record.
//
NewInfo = NULL;
Status = FindUserInfoByType (User, &NewInfo, EFI_USER_INFO_USAGE_DATE_RECORD);
if ((Status == EFI_SUCCESS) || (Status == EFI_NOT_FOUND)) {
Info->InfoType = EFI_USER_INFO_USAGE_DATE_RECORD;
Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;
Info->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_USAGE_DATE);
Status = gRT->GetTime (&Date, NULL);
if (EFI_ERROR (Status)) {
FreePool (Info);
return Status;
}
CopyMem ((UINT8 *) (Info + 1), &Date, sizeof (EFI_USER_INFO_USAGE_DATE));
Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);
if (EFI_ERROR (Status)) {
FreePool (Info);
return Status;
}
}
//
// Update usage count record.
//
UsageCount = 0;
NewInfo = NULL;
Status = FindUserInfoByType (User, &NewInfo, EFI_USER_INFO_USAGE_COUNT_RECORD);
//
// Get usage count.
//
if (Status == EFI_SUCCESS) {
CopyMem (&UsageCount, (UINT8 *) (NewInfo + 1), sizeof (EFI_USER_INFO_USAGE_COUNT));
}
UsageCount++;
if ((Status == EFI_SUCCESS) || (Status == EFI_NOT_FOUND)) {
Info->InfoType = EFI_USER_INFO_USAGE_COUNT_RECORD;
Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;
Info->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_USAGE_COUNT);
CopyMem ((UINT8 *) (Info + 1), &UsageCount, sizeof (EFI_USER_INFO_USAGE_COUNT));
Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);
if (EFI_ERROR (Status)) {
FreePool (Info);
return Status;
}
}
FreePool (Info);
return EFI_SUCCESS;
}
/**
Add a credenetial provider item in form.
@param[in] ProviderGuid Points to the identifir of credential provider.
@param[in] OpCodeHandle Points to container for dynamic created opcodes.
**/
VOID
AddProviderSelection (
IN EFI_GUID *ProviderGuid,
IN VOID *OpCodeHandle
)
{
EFI_HII_HANDLE HiiHandle;
EFI_STRING_ID ProvID;
CHAR16 *ProvStr;
UINTN Index;
EFI_USER_CREDENTIAL2_PROTOCOL *UserCredential;
for (Index = 0; Index < mProviderDb->Count; Index++) {
UserCredential = mProviderDb->Provider[Index];
if (CompareGuid (&UserCredential->Identifier, ProviderGuid)) {
//
// Add credential provider selection.
//
UserCredential->Title (UserCredential, &HiiHandle, &ProvID);
ProvStr = HiiGetString (HiiHandle, ProvID, NULL);
if (ProvStr == NULL) {
continue ;
}
ProvID = HiiSetString (mCallbackInfo->HiiHandle, 0, ProvStr, NULL);
FreePool (ProvStr);
HiiCreateActionOpCode (
OpCodeHandle, // Container for dynamic created opcodes
(EFI_QUESTION_ID)(LABEL_PROVIDER_NAME + Index), // Question ID
ProvID, // Prompt text
STRING_TOKEN (STR_NULL_STRING), // Help text
EFI_IFR_FLAG_CALLBACK, // Question flag
0 // Action String ID
);
break;
}
}
}
/**
Add a username item in form.
@param[in] Index The index of the user in the user name list.
@param[in] User Points to the user profile whose username is added.
@param[in] OpCodeHandle Points to container for dynamic created opcodes.
@retval EFI_SUCCESS Add a username successfully.
@retval Others Fail to add a username.
**/
EFI_STATUS
AddUserSelection (
IN UINT16 Index,
IN USER_PROFILE_ENTRY *User,
IN VOID *OpCodeHandle
)
{
EFI_STRING_ID UserName;
EFI_STATUS Status;
EFI_USER_INFO *UserInfo;
UserInfo = NULL;
Status = FindUserInfoByType (User, &UserInfo, EFI_USER_INFO_NAME_RECORD);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Add user name selection.
//
UserName = HiiSetString (mCallbackInfo->HiiHandle, 0, (EFI_STRING) (UserInfo + 1), NULL);
if (UserName == 0) {
return EFI_OUT_OF_RESOURCES;
}
HiiCreateGotoOpCode (
OpCodeHandle, // Container for dynamic created opcodes
FORMID_PROVIDER_FORM, // Target Form ID
UserName, // Prompt text
STRING_TOKEN (STR_NULL_STRING), // Help text
EFI_IFR_FLAG_CALLBACK, // Question flag
(UINT16) Index // Question ID
);
return EFI_SUCCESS;
}
/**
Identify the user whose identity policy does not contain the operator 'OR'.
@param[in] User Points to the user profile.
@retval EFI_SUCCESS The specified user is identified successfully.
@retval Others Fail to identify the user.
**/
EFI_STATUS
IdentifyAndTypeUser (
IN USER_PROFILE_ENTRY *User
)
{
EFI_STATUS Status;
EFI_USER_INFO *IdentifyInfo;
BOOLEAN Success;
UINTN TotalLen;
UINTN ValueLen;
EFI_USER_INFO_IDENTITY_POLICY *Identity;
//
// Get user identify policy information.
//
IdentifyInfo = NULL;
Status = FindUserInfoByType (User, &IdentifyInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);
if (EFI_ERROR (Status)) {
return Status;
}
ASSERT (IdentifyInfo != NULL);
//
// Check each part of identification policy expression.
//
Success = FALSE;
TotalLen = 0;
while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) {
Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen);
ValueLen = Identity->Length - sizeof (EFI_USER_INFO_IDENTITY_POLICY);
switch (Identity->Type) {
case EFI_USER_INFO_IDENTITY_FALSE:
//
// Check False option.
//
Success = FALSE;
break;
case EFI_USER_INFO_IDENTITY_TRUE:
//
// Check True option.
//
Success = TRUE;
break;
case EFI_USER_INFO_IDENTITY_NOT:
//
// Check negative operation.
//
break;
case EFI_USER_INFO_IDENTITY_AND:
//
// Check and operation.
//
if (!Success) {
return EFI_NOT_READY;
}
Success = FALSE;
break;
case EFI_USER_INFO_IDENTITY_OR:
//
// Check or operation.
//
if (Success) {
return EFI_SUCCESS;
}
break;
case EFI_USER_INFO_IDENTITY_CREDENTIAL_TYPE:
//
// Check credential provider by type.
//
break;
case EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER:
//
// Check credential provider by ID.
//
if (ValueLen != sizeof (EFI_GUID)) {
return EFI_INVALID_PARAMETER;
}
Status = IdentifyByProviderId (User, (EFI_GUID *) (Identity + 1));
if (EFI_ERROR (Status)) {
return Status;
}
Success = TRUE;
break;
default:
return EFI_INVALID_PARAMETER;
break;
}
TotalLen += Identity->Length;
}
if (TotalLen != IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) {
return EFI_INVALID_PARAMETER;
}
if (!Success) {
return EFI_NOT_READY;
}
return EFI_SUCCESS;
}
/**
Identify the user whose identity policy does not contain the operator 'AND'.
@param[in] User Points to the user profile.
@retval EFI_SUCCESS The specified user is identified successfully.
@retval Others Fail to identify the user.
**/
EFI_STATUS
IdentifyOrTypeUser (
IN USER_PROFILE_ENTRY *User
)
{
EFI_STATUS Status;
EFI_USER_INFO *IdentifyInfo;
UINTN TotalLen;
UINTN ValueLen;
EFI_USER_INFO_IDENTITY_POLICY *Identity;
VOID *StartOpCodeHandle;
VOID *EndOpCodeHandle;
EFI_IFR_GUID_LABEL *StartLabel;
EFI_IFR_GUID_LABEL *EndLabel;
//
// Get user identify policy information.
//
IdentifyInfo = NULL;
Status = FindUserInfoByType (User, &IdentifyInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);
if (EFI_ERROR (Status)) {
return Status;
}
ASSERT (IdentifyInfo != NULL);
//
// Initialize the container for dynamic opcodes.
//
StartOpCodeHandle = HiiAllocateOpCodeHandle ();
ASSERT (StartOpCodeHandle != NULL);
EndOpCodeHandle = HiiAllocateOpCodeHandle ();
ASSERT (EndOpCodeHandle != NULL);
//
// Create Hii Extend Label OpCode.
//
StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
StartOpCodeHandle,
&gEfiIfrTianoGuid,
NULL,
sizeof (EFI_IFR_GUID_LABEL)
);
StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
StartLabel->Number = LABEL_PROVIDER_NAME;
EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
EndOpCodeHandle,
&gEfiIfrTianoGuid,
NULL,
sizeof (EFI_IFR_GUID_LABEL)
);
EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
EndLabel->Number = LABEL_END;
//
// Add the providers that exists in the user's policy.
//
TotalLen = 0;
while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) {
Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen);
ValueLen = Identity->Length - sizeof (EFI_USER_INFO_IDENTITY_POLICY);
if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) {
AddProviderSelection ((EFI_GUID *) (Identity + 1), StartOpCodeHandle);
}
TotalLen += Identity->Length;
}
HiiUpdateForm (
mCallbackInfo->HiiHandle, // HII handle
&gUserIdentifyManagerGuid,// Formset GUID
FORMID_PROVIDER_FORM, // Form ID
StartOpCodeHandle, // Label for where to insert opcodes
EndOpCodeHandle // Replace data
);
HiiFreeOpCodeHandle (StartOpCodeHandle);
HiiFreeOpCodeHandle (EndOpCodeHandle);
return EFI_SUCCESS;
}
/**
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 Others Fail to handle the action.
**/
EFI_STATUS
EFIAPI
UserIdentifyManagerCallback (
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;
USER_PROFILE_ENTRY *User;
UINT8 PolicyType;
UINT16 Index;
VOID *StartOpCodeHandle;
VOID *EndOpCodeHandle;
EFI_IFR_GUID_LABEL *StartLabel;
EFI_IFR_GUID_LABEL *EndLabel;
Status = EFI_SUCCESS;
switch (Action) {
case EFI_BROWSER_ACTION_FORM_OPEN:
{
//
// Update user Form when user Form is opened.
// This will be done only in FORM_OPEN CallBack of question with FORM_OPEN_QUESTION_ID from user Form.
//
if (QuestionId != FORM_OPEN_QUESTION_ID) {
return EFI_SUCCESS;
}
//
// Initialize the container for dynamic opcodes.
//
StartOpCodeHandle = HiiAllocateOpCodeHandle ();
ASSERT (StartOpCodeHandle != NULL);
EndOpCodeHandle = HiiAllocateOpCodeHandle ();
ASSERT (EndOpCodeHandle != NULL);
//
// Create Hii Extend Label OpCode.
//
StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
StartOpCodeHandle,
&gEfiIfrTianoGuid,
NULL,
sizeof (EFI_IFR_GUID_LABEL)
);
StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
StartLabel->Number = LABEL_USER_NAME;
EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
EndOpCodeHandle,
&gEfiIfrTianoGuid,
NULL,
sizeof (EFI_IFR_GUID_LABEL)
);
EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
EndLabel->Number = LABEL_END;
//
// Add all the user profile in the user profile database.
//
for (Index = 0; Index < mUserProfileDb->UserProfileNum; Index++) {
User = (USER_PROFILE_ENTRY *) mUserProfileDb->UserProfile[Index];
AddUserSelection ((UINT16)(LABEL_USER_NAME + Index), User, StartOpCodeHandle);
}
HiiUpdateForm (
mCallbackInfo->HiiHandle, // HII handle
&gUserIdentifyManagerGuid,// Formset GUID
FORMID_USER_FORM, // Form ID
StartOpCodeHandle, // Label for where to insert opcodes
EndOpCodeHandle // Replace data
);
HiiFreeOpCodeHandle (StartOpCodeHandle);
HiiFreeOpCodeHandle (EndOpCodeHandle);
return EFI_SUCCESS;
}
break;
case EFI_BROWSER_ACTION_FORM_CLOSE:
Status = EFI_SUCCESS;
break;
case EFI_BROWSER_ACTION_CHANGED:
if (QuestionId >= LABEL_PROVIDER_NAME) {
//
// QuestionId comes from the second Form (Select a Credential Provider if identity
// policy is OR type). Identify the user by the selected provider.
//
Status = IdentifyByProviderId (mCurrentUser, &mProviderDb->Provider[QuestionId & 0xFFF]->Identifier);
if (Status == EFI_SUCCESS) {
mIdentified = TRUE;
*ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
}
return EFI_SUCCESS;
}
break;
case EFI_BROWSER_ACTION_CHANGING:
//
// QuestionId comes from the first Form (Select a user to identify).
//
if (QuestionId >= LABEL_PROVIDER_NAME) {
return EFI_SUCCESS;
}
User = (USER_PROFILE_ENTRY *) mUserProfileDb->UserProfile[QuestionId & 0xFFF];
Status = GetIdentifyType (User, &PolicyType);
if (EFI_ERROR (Status)) {
return Status;
}
if (PolicyType == EFI_USER_INFO_IDENTITY_OR) {
//
// Identify the user by "OR" logical.
//
Status = IdentifyOrTypeUser (User);
if (EFI_ERROR (Status)) {
return Status;
}
mCurrentUser = (EFI_USER_PROFILE_HANDLE) User;
} else {
//
// Identify the user by "AND" logical.
//
Status = IdentifyAndTypeUser (User);
if (EFI_ERROR (Status)) {
return Status;
}
mCurrentUser = (EFI_USER_PROFILE_HANDLE) User;
mIdentified = TRUE;
if (Type == EFI_IFR_TYPE_REF) {
Value->ref.FormId = FORMID_INVALID_FORM;
}
}
break;
default:
//
// All other action return unsupported.
//
Status = EFI_UNSUPPORTED;
break;
}
return Status;
}
/**
This function construct user profile database from user data saved in the Flash.
If no user is found in Flash, add one default user "administrator" in the user
profile database.
@retval EFI_SUCCESS Init user profile database successfully.
@retval Others Fail to init user profile database.
**/
EFI_STATUS
InitUserProfileDb (
VOID
)
{
EFI_STATUS Status;
UINT8 *VarData;
UINTN VarSize;
UINTN CurVarSize;
CHAR16 VarName[10];
UINTN Index;
UINT32 VarAttr;
if (mUserProfileDb != NULL) {
//
// The user profiles had been already initialized.
//
return EFI_SUCCESS;
}
//
// Init user profile database structure.
//
if (!ExpandUsermUserProfileDb ()) {
return EFI_OUT_OF_RESOURCES;
}
CurVarSize = DEFAULT_PROFILE_SIZE;
VarData = AllocateZeroPool (CurVarSize);
if (VarData == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Get all user proifle entries.
//
Index = 0;
while (TRUE) {
//
// Get variable name.
//
UnicodeSPrint (
VarName,
sizeof (VarName),
L"User%04x",
Index
);
Index++;
//
// Get variable value.
//
VarSize = CurVarSize;
Status = gRT->GetVariable (VarName, &gUserIdentifyManagerGuid, &VarAttr, &VarSize, VarData);
if (Status == EFI_BUFFER_TOO_SMALL) {
FreePool (VarData);
VarData = AllocatePool (VarSize);
if (VarData == NULL) {
Status = EFI_OUT_OF_RESOURCES;
break;
}
CurVarSize = VarSize;
Status = gRT->GetVariable (VarName, &gUserIdentifyManagerGuid, &VarAttr, &VarSize, VarData);
}
if (EFI_ERROR (Status)) {
if (Status == EFI_NOT_FOUND) {
Status = EFI_SUCCESS;
}
break;
}
//
// Check variable attributes.
//
if (VarAttr != (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS)) {
Status = gRT->SetVariable (VarName, &gUserIdentifyManagerGuid, VarAttr, 0, NULL);
continue;
}
//
// Add user profile to the user profile database.
//
Status = AddUserProfile (NULL, VarSize, VarData, FALSE);
if (EFI_ERROR (Status)) {
if (Status == EFI_SECURITY_VIOLATION) {
//
// Delete invalid user profile
//
gRT->SetVariable (VarName, &gUserIdentifyManagerGuid, VarAttr, 0, NULL);
} else if (Status == EFI_OUT_OF_RESOURCES) {
break;
}
} else {
//
// Delete and save the profile again if some invalid profiles are deleted.
//
if (mUserProfileDb->UserProfileNum < Index) {
gRT->SetVariable (VarName, &gUserIdentifyManagerGuid, VarAttr, 0, NULL);
SaveNvUserProfile (mUserProfileDb->UserProfile[mUserProfileDb->UserProfileNum - 1], FALSE);
}
}
}
if (VarData != NULL) {
FreePool (VarData);
}
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check whether the user profile database is empty.
//
if (mUserProfileDb->UserProfileNum == 0) {
Status = AddDefaultUserProfile ();
}
return Status;
}
/**
This function collects all the credential providers and saves to mProviderDb.
@retval EFI_SUCCESS Collect credential providers successfully.
@retval Others Fail to collect credential providers.
**/
EFI_STATUS
InitProviderInfo (
VOID
)
{
EFI_STATUS Status;
UINTN HandleCount;
EFI_HANDLE *HandleBuf;
UINTN Index;
if (mProviderDb != NULL) {
//
// The credential providers had been collected before.
//
return EFI_SUCCESS;
}
//
// Try to find all the user credential provider driver.
//
HandleCount = 0;
HandleBuf = NULL;
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiUserCredential2ProtocolGuid,
NULL,
&HandleCount,
&HandleBuf
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get provider infomation.
//
mProviderDb = AllocateZeroPool (
sizeof (CREDENTIAL_PROVIDER_INFO) -
sizeof (EFI_USER_CREDENTIAL2_PROTOCOL *) +
HandleCount * sizeof (EFI_USER_CREDENTIAL2_PROTOCOL *)
);
if (mProviderDb == NULL) {
FreePool (HandleBuf);
return EFI_OUT_OF_RESOURCES;
}
mProviderDb->Count = HandleCount;
for (Index = 0; Index < HandleCount; Index++) {
Status = gBS->HandleProtocol (
HandleBuf[Index],
&gEfiUserCredential2ProtocolGuid,
(VOID **) &mProviderDb->Provider[Index]
);
if (EFI_ERROR (Status)) {
FreePool (HandleBuf);
FreePool (mProviderDb);
mProviderDb = NULL;
return Status;
}
}
FreePool (HandleBuf);
return EFI_SUCCESS;
}
/**
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
FakeExtractConfig (
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
FakeRouteConfig (
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;
}
return EFI_NOT_FOUND;
}
/**
This function initialize the data mainly used in form browser.
@retval EFI_SUCCESS Initialize form data successfully.
@retval Others Fail to Initialize form data.
**/
EFI_STATUS
InitFormBrowser (
VOID
)
{
EFI_STATUS Status;
USER_MANAGER_CALLBACK_INFO *CallbackInfo;
EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
EFI_HII_STRING_PROTOCOL *HiiString;
EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
//
// Initialize driver private data.
//
CallbackInfo = AllocateZeroPool (sizeof (USER_MANAGER_CALLBACK_INFO));
if (CallbackInfo == NULL) {
return EFI_OUT_OF_RESOURCES;
}
CallbackInfo->Signature = USER_MANAGER_SIGNATURE;
CallbackInfo->ConfigAccess.ExtractConfig = FakeExtractConfig;
CallbackInfo->ConfigAccess.RouteConfig = FakeRouteConfig;
CallbackInfo->ConfigAccess.Callback = UserIdentifyManagerCallback;
//
// Locate Hii Database protocol.
//
Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &HiiDatabase);
if (EFI_ERROR (Status)) {
return Status;
}
CallbackInfo->HiiDatabase = HiiDatabase;
//
// Locate HiiString protocol.
//
Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &HiiString);
if (EFI_ERROR (Status)) {
return Status;
}
CallbackInfo->HiiString = HiiString;
//
// Locate Formbrowser2 protocol.
//
Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
if (EFI_ERROR (Status)) {
return Status;
}
CallbackInfo->FormBrowser2 = FormBrowser2;
CallbackInfo->DriverHandle = NULL;
//
// Install Device Path Protocol and Config Access protocol to driver handle.
//
Status = gBS->InstallMultipleProtocolInterfaces (
&CallbackInfo->DriverHandle,
&gEfiDevicePathProtocolGuid,
&mHiiVendorDevicePath,
&gEfiHiiConfigAccessProtocolGuid,
&CallbackInfo->ConfigAccess,
NULL
);
ASSERT_EFI_ERROR (Status);
//
// Publish HII data.
//
CallbackInfo->HiiHandle = HiiAddPackages (
&gUserIdentifyManagerGuid,
CallbackInfo->DriverHandle,
UserIdentifyManagerStrings,
UserIdentifyManagerVfrBin,
NULL
);
if (CallbackInfo->HiiHandle == NULL) {
return EFI_OUT_OF_RESOURCES;
}
mCallbackInfo = CallbackInfo;
return EFI_SUCCESS;
}
/**
Identify the user whose identification policy supports auto logon.
@param[in] ProviderIndex The provider index in the provider list.
@param[out] User Points to user user profile if a user is identified successfully.
@retval EFI_SUCCESS Identify a user with the specified provider successfully.
@retval Others Fail to identify a user.
**/
EFI_STATUS
IdentifyAutoLogonUser (
IN UINTN ProviderIndex,
OUT USER_PROFILE_ENTRY **User
)
{
EFI_STATUS Status;
EFI_USER_INFO *Info;
UINT8 PolicyType;
Info = AllocateZeroPool (sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_IDENTIFIER));
if (Info == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Info->InfoType = EFI_USER_INFO_IDENTIFIER_RECORD;
Info->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_IDENTIFIER);
//
// Identify the specified credential provider's auto logon user.
//
Status = mProviderDb->Provider[ProviderIndex]->User (
mProviderDb->Provider[ProviderIndex],
NULL,
(EFI_USER_INFO_IDENTIFIER *) (Info + 1)
);
if (EFI_ERROR (Status)) {
FreePool (Info);
return Status;
}
//
// Find user with the specified user ID.
//
*User = NULL;
Status = FindUserProfileByInfo (User, NULL, Info, Info->InfoSize);
FreePool (Info);
if (EFI_ERROR (Status)) {
return Status;
}
Status = GetIdentifyType ((EFI_USER_PROFILE_HANDLE) * User, &PolicyType);
if (PolicyType == EFI_USER_INFO_IDENTITY_AND) {
//
// The identified user need also identified by other credential provider.
// This can handle through select user.
//
return EFI_NOT_READY;
}
return Status;
}
/**
Check whether the given console is ready.
@param[in] ProtocolGuid Points to the protocol guid of sonsole .
@retval TRUE The given console is ready.
@retval FALSE The given console is not ready.
**/
BOOLEAN
CheckConsole (
EFI_GUID *ProtocolGuid
)
{
EFI_STATUS Status;
UINTN HandleCount;
EFI_HANDLE *HandleBuf;
UINTN Index;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
//
// Try to find all the handle driver.
//
HandleCount = 0;
HandleBuf = NULL;
Status = gBS->LocateHandleBuffer (
ByProtocol,
ProtocolGuid,
NULL,
&HandleCount,
&HandleBuf
);
if (EFI_ERROR (Status)) {
return FALSE;
}
for (Index = 0; Index < HandleCount; Index++) {
DevicePath = DevicePathFromHandle (HandleBuf[Index]);
if (DevicePath != NULL) {
FreePool (HandleBuf);
return TRUE;
}
}
FreePool (HandleBuf);
return FALSE;
}
/**
Check whether the console is ready.
@retval TRUE The console is ready.
@retval FALSE The console is not ready.
**/
BOOLEAN
IsConsoleReady (
VOID
)
{
if (!CheckConsole (&gEfiSimpleTextOutProtocolGuid)) {
return FALSE;
}
if (!CheckConsole (&gEfiSimpleTextInProtocolGuid)) {
if (!CheckConsole (&gEfiSimpleTextInputExProtocolGuid)) {
return FALSE;
}
}
return TRUE;
}
/**
Identify a user to logon.
@param[out] User Points to user user profile if a user is identified successfully.
@retval EFI_SUCCESS Identify a user successfully.
**/
EFI_STATUS
IdentifyUser (
OUT USER_PROFILE_ENTRY **User
)
{
EFI_STATUS Status;
UINTN Index;
EFI_CREDENTIAL_LOGON_FLAGS AutoLogon;
EFI_USER_INFO *IdentifyInfo;
EFI_USER_INFO_IDENTITY_POLICY *Identity;
EFI_USER_CREDENTIAL2_PROTOCOL *UserCredential;
USER_PROFILE_ENTRY *UserEntry;
//
// Initialize credential providers.
//
InitProviderInfo ();
//
// Initialize user profile database.
//
InitUserProfileDb ();
//
// If only one user in system, and its identify policy is TRUE, then auto logon.
//
if (mUserProfileDb->UserProfileNum == 1) {
UserEntry = (USER_PROFILE_ENTRY *) mUserProfileDb->UserProfile[0];
IdentifyInfo = NULL;
Status = FindUserInfoByType (UserEntry, &IdentifyInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);
if (EFI_ERROR (Status)) {
return Status;
}
ASSERT (IdentifyInfo != NULL);
Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1));
if (Identity->Type == EFI_USER_INFO_IDENTITY_TRUE) {
mCurrentUser = (EFI_USER_PROFILE_HANDLE) UserEntry;
UpdateUserInfo (UserEntry);
*User = UserEntry;
return EFI_SUCCESS;
}
}
//
// Find and login the default & AutoLogon user.
//
for (Index = 0; Index < mProviderDb->Count; Index++) {
UserCredential = mProviderDb->Provider[Index];
Status = UserCredential->Default (UserCredential, &AutoLogon);
if (EFI_ERROR (Status)) {
continue;
}
if ((AutoLogon & (EFI_CREDENTIAL_LOGON_FLAG_DEFAULT | EFI_CREDENTIAL_LOGON_FLAG_AUTO)) != 0) {
Status = IdentifyAutoLogonUser (Index, &UserEntry);
if (Status == EFI_SUCCESS) {
mCurrentUser = (EFI_USER_PROFILE_HANDLE) UserEntry;
UpdateUserInfo (UserEntry);
*User = UserEntry;
return EFI_SUCCESS;
}
}
}
if (!IsConsoleReady ()) {
//
// The console is still not ready for user selection.
//
return EFI_ACCESS_DENIED;
}
//
// Select a user and identify it.
//
mCallbackInfo->FormBrowser2->SendForm (
mCallbackInfo->FormBrowser2,
&mCallbackInfo->HiiHandle,
1,
&gUserIdentifyManagerGuid,
0,
NULL,
NULL
);
if (mIdentified) {
*User = (USER_PROFILE_ENTRY *) mCurrentUser;
UpdateUserInfo (*User);
return EFI_SUCCESS;
}
return EFI_ACCESS_DENIED;
}
/**
An empty function to pass error checking of CreateEventEx ().
@param Event Event whose notification function is being invoked.
@param Context Pointer to the notification function's context,
which is implementation-dependent.
**/
VOID
EFIAPI
InternalEmptyFuntion (
IN EFI_EVENT Event,
IN VOID *Context
)
{
}
/**
Create, Signal, and Close the User Profile Changed event.
**/
VOID
SignalEventUserProfileChanged (
VOID
)
{
EFI_STATUS Status;
EFI_EVENT Event;
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
InternalEmptyFuntion,
NULL,
&gEfiEventUserProfileChangedGuid,
&Event
);
ASSERT_EFI_ERROR (Status);
gBS->SignalEvent (Event);
gBS->CloseEvent (Event);
}
/**
Create a new user profile.
This function creates a new user profile with only a new user identifier attached and returns
its handle. The user profile is non-volatile, but the handle User can change across reboots.
@param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL.
@param[out] User On return, points to the new user profile handle.
The user profile handle is unique only during this boot.
@retval EFI_SUCCESS User profile was successfully created.
@retval EFI_ACCESS_DENIED Current user does not have sufficient permissions to create a
user profile.
@retval EFI_UNSUPPORTED Creation of new user profiles is not supported.
@retval EFI_INVALID_PARAMETER The User parameter is NULL.
**/
EFI_STATUS
EFIAPI
UserProfileCreate (
IN CONST EFI_USER_MANAGER_PROTOCOL *This,
OUT EFI_USER_PROFILE_HANDLE *User
)
{
EFI_STATUS Status;
if ((This == NULL) || (User == NULL)) {
return EFI_INVALID_PARAMETER;
}
//
// Check the right of the current user.
//
if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_MANAGE)) {
if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_ENROLL_OTHERS)) {
return EFI_ACCESS_DENIED;
}
}
//
// Create new user profile
//
Status = CreateUserProfile ((USER_PROFILE_ENTRY **) User);
if (EFI_ERROR (Status)) {
return EFI_ACCESS_DENIED;
}
return EFI_SUCCESS;
}
/**
Delete an existing user profile.
@param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL.
@param[in] User User profile handle.
@retval EFI_SUCCESS User profile was successfully deleted.
@retval EFI_ACCESS_DENIED Current user does not have sufficient permissions to delete a user
profile or there is only one user profile.
@retval EFI_UNSUPPORTED Deletion of new user profiles is not supported.
@retval EFI_INVALID_PARAMETER User does not refer to a valid user profile.
**/
EFI_STATUS
EFIAPI
UserProfileDelete (
IN CONST EFI_USER_MANAGER_PROTOCOL *This,
IN EFI_USER_PROFILE_HANDLE User
)
{
EFI_STATUS Status;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Check the right of the current user.
//
if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_MANAGE)) {
return EFI_ACCESS_DENIED;
}
//
// Delete user profile.
//
Status = DelUserProfile (User);
if (EFI_ERROR (Status)) {
if (Status != EFI_INVALID_PARAMETER) {
return EFI_ACCESS_DENIED;
}
return EFI_INVALID_PARAMETER;
}
return EFI_SUCCESS;
}
/**
Enumerate all of the enrolled users on the platform.
This function returns the next enrolled user profile. To retrieve the first user profile handle,
point User at a NULL. Each subsequent call will retrieve another user profile handle until there
are no more, at which point User will point to NULL.
@param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL.
@param[in, out] User On entry, points to the previous user profile handle or NULL to
start enumeration. On exit, points to the next user profile handle
or NULL if there are no more user profiles.
@retval EFI_SUCCESS Next enrolled user profile successfully returned.
@retval EFI_ACCESS_DENIED Next enrolled user profile was not successfully returned.
@retval EFI_INVALID_PARAMETER The User parameter is NULL.
**/
EFI_STATUS
EFIAPI
UserProfileGetNext (
IN CONST EFI_USER_MANAGER_PROTOCOL *This,
IN OUT EFI_USER_PROFILE_HANDLE *User
)
{
EFI_STATUS Status;
if ((This == NULL) || (User == NULL)) {
return EFI_INVALID_PARAMETER;
}
Status = FindUserProfile ((USER_PROFILE_ENTRY **) User, TRUE, NULL);
if (EFI_ERROR (Status)) {
return EFI_ACCESS_DENIED;
}
return EFI_SUCCESS;
}
/**
Return the current user profile handle.
@param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL.
@param[out] CurrentUser On return, points to the current user profile handle.
@retval EFI_SUCCESS Current user profile handle returned successfully.
@retval EFI_INVALID_PARAMETER The CurrentUser parameter is NULL.
**/
EFI_STATUS
EFIAPI
UserProfileCurrent (
IN CONST EFI_USER_MANAGER_PROTOCOL *This,
OUT EFI_USER_PROFILE_HANDLE *CurrentUser
)
{
//
// Get current user profile.
//
if ((This == NULL) || (CurrentUser == NULL)) {
return EFI_INVALID_PARAMETER;
}
*CurrentUser = mCurrentUser;
return EFI_SUCCESS;
}
/**
Identify a user.
Identify the user and, if authenticated, returns the user handle and changes the current
user profile. All user information marked as private in a previously selected profile
is no longer available for inspection.
Whenever the current user profile is changed then the an event with the GUID
EFI_EVENT_GROUP_USER_PROFILE_CHANGED is signaled.
@param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL.
@param[out] User On return, points to the user profile handle for the current
user profile.
@retval EFI_SUCCESS User was successfully identified.
@retval EFI_ACCESS_DENIED User was not successfully identified.
@retval EFI_INVALID_PARAMETER The User parameter is NULL.
**/
EFI_STATUS
EFIAPI
UserProfileIdentify (
IN CONST EFI_USER_MANAGER_PROTOCOL *This,
OUT EFI_USER_PROFILE_HANDLE *User
)
{
EFI_STATUS Status;
if ((This == NULL) || (User == NULL)) {
return EFI_INVALID_PARAMETER;
}
if (mCurrentUser != NULL) {
*User = mCurrentUser;
return EFI_SUCCESS;
}
//
// Identify user
//
Status = IdentifyUser ((USER_PROFILE_ENTRY **) User);
if (EFI_ERROR (Status)) {
return EFI_ACCESS_DENIED;
}
//
// Publish the user info into the EFI system configuration table.
//
PublishUserTable ();
//
// Signal User Profile Changed event.
//
SignalEventUserProfileChanged ();
return EFI_SUCCESS;
}
/**
Find a user using a user information record.
This function searches all user profiles for the specified user information record.
The search starts with the user information record handle following UserInfo and
continues until either the information is found or there are no more user profiles.
A match occurs when the Info.InfoType field matches the user information record
type and the user information record data matches the portion of Info.
@param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL.
@param[in, out] User On entry, points to the previously returned user profile
handle, or NULL to start searching with the first user profile.
On return, points to the user profile handle, or NULL if not
found.
@param[in, out] UserInfo On entry, points to the previously returned user information
handle, or NULL to start searching with the first. On return,
points to the user information handle of the user information
record, or NULL if not found. Can be NULL, in which case only
one user information record per user can be returned.
@param[in] Info Points to the buffer containing the user information to be
compared to the user information record. If the user information
record data is empty, then only the user information record type
is compared. If InfoSize is 0, then the user information record
must be empty.
@param[in] InfoSize The size of Info, in bytes.
@retval EFI_SUCCESS User information was found. User points to the user profile
handle, and UserInfo points to the user information handle.
@retval EFI_NOT_FOUND User information was not found. User points to NULL, and
UserInfo points to NULL.
@retval EFI_INVALID_PARAMETER User is NULL. Or Info is NULL.
**/
EFI_STATUS
EFIAPI
UserProfileFind (
IN CONST EFI_USER_MANAGER_PROTOCOL *This,
IN OUT EFI_USER_PROFILE_HANDLE *User,
IN OUT EFI_USER_INFO_HANDLE *UserInfo OPTIONAL,
IN CONST EFI_USER_INFO *Info,
IN UINTN InfoSize
)
{
EFI_STATUS Status;
UINTN Size;
if ((This == NULL) || (User == NULL) || (Info == NULL)) {
return EFI_INVALID_PARAMETER;
}
if (InfoSize == 0) {
//
// If InfoSize is 0, then the user information record must be empty.
//
if (Info->InfoSize != sizeof (EFI_USER_INFO)) {
return EFI_INVALID_PARAMETER;
}
} else {
if (InfoSize != Info->InfoSize) {
return EFI_INVALID_PARAMETER;
}
}
Size = Info->InfoSize;
//
// Find user profile accdoring to user information.
//
Status = FindUserProfileByInfo (
(USER_PROFILE_ENTRY **) User,
(EFI_USER_INFO **) UserInfo,
(EFI_USER_INFO *) Info,
Size
);
if (EFI_ERROR (Status)) {
*User = NULL;
if (UserInfo != NULL) {
*UserInfo = NULL;
}
return EFI_NOT_FOUND;
}
return EFI_SUCCESS;
}
/**
Return information attached to the user.
This function returns user information. The format of the information is described in User
Information. The function may return EFI_ACCESS_DENIED if the information is marked private
and the handle specified by User is not the current user profile. The function may return
EFI_ACCESS_DENIED if the information is marked protected and the information is associated
with a credential provider for which the user has not been authenticated.
@param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL.
@param[in] User Handle of the user whose profile will be retrieved.
@param[in] UserInfo Handle of the user information data record.
@param[out] Info On entry, points to a buffer of at least *InfoSize bytes. On exit,
holds the user information. If the buffer is too small to hold the
information, then EFI_BUFFER_TOO_SMALL is returned and InfoSize is
updated to contain the number of bytes actually required.
@param[in, out] InfoSize On entry, points to the size of Info. On return, points to the size
of the user information.
@retval EFI_SUCCESS Information returned successfully.
@retval EFI_ACCESS_DENIED The information about the specified user cannot be accessed by the
current user.
@retval EFI_BUFFER_TOO_SMALL The number of bytes specified by *InfoSize is too small to hold the
returned data. The actual size required is returned in *InfoSize.
@retval EFI_NOT_FOUND User does not refer to a valid user profile or UserInfo does not refer
to a valid user info handle.
@retval EFI_INVALID_PARAMETER Info is NULL or InfoSize is NULL.
**/
EFI_STATUS
EFIAPI
UserProfileGetInfo (
IN CONST EFI_USER_MANAGER_PROTOCOL *This,
IN EFI_USER_PROFILE_HANDLE User,
IN EFI_USER_INFO_HANDLE UserInfo,
OUT EFI_USER_INFO *Info,
IN OUT UINTN *InfoSize
)
{
EFI_STATUS Status;
if ((This == NULL) || (InfoSize == NULL)) {
return EFI_INVALID_PARAMETER;
}
if ((*InfoSize != 0) && (Info == NULL)) {
return EFI_INVALID_PARAMETER;
}
if ((User == NULL) || (UserInfo == NULL)) {
return EFI_NOT_FOUND;
}
Status = GetUserInfo (User, UserInfo, Info, InfoSize, TRUE);
if (EFI_ERROR (Status)) {
if (Status == EFI_BUFFER_TOO_SMALL) {
return EFI_BUFFER_TOO_SMALL;
}
return EFI_ACCESS_DENIED;
}
return EFI_SUCCESS;
}
/**
Add or update user information.
This function changes user information. If NULL is pointed to by UserInfo, then a new user
information record is created and its handle is returned in UserInfo. Otherwise, the existing
one is replaced.
If EFI_USER_INFO_IDENITTY_POLICY_RECORD is changed, it is the caller's responsibility to keep
it to be synced with the information on credential providers.
If EFI_USER_INFO_EXCLUSIVE is specified in Info and a user information record of the same
type already exists in the user profile, then EFI_ACCESS_DENIED will be returned and UserInfo
will point to the handle of the existing record.
@param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL.
@param[in] User Handle of the user whose profile will be retrieved.
@param[in, out] UserInfo Handle of the user information data record.
@param[in] Info On entry, points to a buffer of at least *InfoSize bytes. On exit,
holds the user information. If the buffer is too small to hold the
information, then EFI_BUFFER_TOO_SMALL is returned and InfoSize is
updated to contain the number of bytes actually required.
@param[in] InfoSize On entry, points to the size of Info. On return, points to the size
of the user information.
@retval EFI_SUCCESS Information returned successfully.
@retval EFI_ACCESS_DENIED The record is exclusive.
@retval EFI_SECURITY_VIOLATION The current user does not have permission to change the specified
user profile or user information record.
@retval EFI_NOT_FOUND User does not refer to a valid user profile or UserInfo does not
refer to a valid user info handle.
@retval EFI_INVALID_PARAMETER UserInfo is NULL or Info is NULL.
**/
EFI_STATUS
EFIAPI
UserProfileSetInfo (
IN CONST EFI_USER_MANAGER_PROTOCOL *This,
IN EFI_USER_PROFILE_HANDLE User,
IN OUT EFI_USER_INFO_HANDLE *UserInfo,
IN CONST EFI_USER_INFO *Info,
IN UINTN InfoSize
)
{
EFI_STATUS Status;
if ((This == NULL) || (User == NULL) || (UserInfo == NULL) || (Info == NULL)) {
return EFI_INVALID_PARAMETER;
}
//
// Check the right of the current user.
//
if (User != mCurrentUser) {
if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_MANAGE)) {
if (*UserInfo != NULL) {
//
// Can't update info in other profiles without MANAGE right.
//
return EFI_SECURITY_VIOLATION;
}
if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_ENROLL_OTHERS)) {
//
// Can't add info into other profiles.
//
return EFI_SECURITY_VIOLATION;
}
}
}
if (User == mCurrentUser) {
if (CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_ENROLL_SELF)) {
//
// Only identify policy can be added/updated.
//
if (Info->InfoType != EFI_USER_INFO_IDENTITY_POLICY_RECORD) {
return EFI_SECURITY_VIOLATION;
}
}
}
//
// Modify user information.
//
Status = ModifyUserInfo (User, (EFI_USER_INFO **) UserInfo, Info, InfoSize);
if (EFI_ERROR (Status)) {
if (Status == EFI_ACCESS_DENIED) {
return EFI_ACCESS_DENIED;
}
return EFI_SECURITY_VIOLATION;
}
return EFI_SUCCESS;
}
/**
Called by credential provider to notify of information change.
This function allows the credential provider to notify the User Identity Manager when user status
has changed.
If the User Identity Manager doesn't support asynchronous changes in credentials, then this function
should return EFI_UNSUPPORTED.
If current user does not exist, and the credential provider can identify a user, then make the user
to be current user and signal the EFI_EVENT_GROUP_USER_PROFILE_CHANGED event.
If current user already exists, and the credential provider can identify another user, then switch
current user to the newly identified user, and signal the EFI_EVENT_GROUP_USER_PROFILE_CHANGED event.
If current user was identified by this credential provider and now the credential provider cannot identify
current user, then logout current user and signal the EFI_EVENT_GROUP_USER_PROFILE_CHANGED event.
@param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL.
@param[in] Changed Handle on which is installed an instance of the EFI_USER_CREDENTIAL2_PROTOCOL
where the user has changed.
@retval EFI_SUCCESS The User Identity Manager has handled the notification.
@retval EFI_NOT_READY The function was called while the specified credential provider was not selected.
@retval EFI_UNSUPPORTED The User Identity Manager doesn't support asynchronous notifications.
**/
EFI_STATUS
EFIAPI
UserProfileNotify (
IN CONST EFI_USER_MANAGER_PROTOCOL *This,
IN EFI_HANDLE Changed
)
{
return EFI_UNSUPPORTED;
}
/**
Delete user information.
Delete the user information attached to the user profile specified by the UserInfo.
@param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL.
@param[in] User Handle of the user whose information will be deleted.
@param[in] UserInfo Handle of the user information to remove.
@retval EFI_SUCCESS User information deleted successfully.
@retval EFI_NOT_FOUND User information record UserInfo does not exist in the user profile.
@retval EFI_ACCESS_DENIED The current user does not have permission to delete this user information.
**/
EFI_STATUS
EFIAPI
UserProfileDeleteInfo (
IN CONST EFI_USER_MANAGER_PROTOCOL *This,
IN EFI_USER_PROFILE_HANDLE User,
IN EFI_USER_INFO_HANDLE UserInfo
)
{
EFI_STATUS Status;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Check the right of the current user.
//
if (User != mCurrentUser) {
if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_MANAGE)) {
return EFI_ACCESS_DENIED;
}
}
//
// Delete user information.
//
Status = DelUserInfo (User, UserInfo, TRUE);
if (EFI_ERROR (Status)) {
if (Status == EFI_NOT_FOUND) {
return EFI_NOT_FOUND;
}
return EFI_ACCESS_DENIED;
}
return EFI_SUCCESS;
}
/**
Enumerate user information of all the enrolled users on the platform.
This function returns the next user information record. To retrieve the first user
information record handle, point UserInfo at a NULL. Each subsequent call will retrieve
another user information record handle until there are no more, at which point UserInfo
will point to NULL.
@param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL.
@param[in] User Handle of the user whose information will be deleted.
@param[in, out] UserInfo Handle of the user information to remove.
@retval EFI_SUCCESS User information returned.
@retval EFI_NOT_FOUND No more user information found.
@retval EFI_INVALID_PARAMETER UserInfo is NULL.
**/
EFI_STATUS
EFIAPI
UserProfileGetNextInfo (
IN CONST EFI_USER_MANAGER_PROTOCOL *This,
IN EFI_USER_PROFILE_HANDLE User,
IN OUT EFI_USER_INFO_HANDLE *UserInfo
)
{
if ((This == NULL) || (UserInfo == NULL)) {
return EFI_INVALID_PARAMETER;
}
//
// Get next user information entry.
//
return FindUserInfo (User, (EFI_USER_INFO **) UserInfo, TRUE, NULL);
}
/**
Main entry for this driver.
@param[in] ImageHandle Image handle this driver.
@param[in] SystemTable Pointer to SystemTable.
@retval EFI_SUCESS This function always complete successfully.
**/
EFI_STATUS
EFIAPI
UserIdentifyManagerInit (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//
// It is NOT robust enough to be included in production.
//
#error "This implementation is just a sample, please comment this line if you really want to use this driver."
//
// Initiate form browser.
//
InitFormBrowser ();
//
// Install protocol interfaces for the User Identity Manager.
//
Status = gBS->InstallProtocolInterface (
&mCallbackInfo->DriverHandle,
&gEfiUserManagerProtocolGuid,
EFI_NATIVE_INTERFACE,
&gUserIdentifyManager
);
ASSERT_EFI_ERROR (Status);
LoadDeferredImageInit (ImageHandle);
return EFI_SUCCESS;
}