diff options
Diffstat (limited to 'SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.c')
-rw-r--r-- | SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.c | 4381 |
1 files changed, 4381 insertions, 0 deletions
diff --git a/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.c b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.c new file mode 100644 index 0000000000..e105579115 --- /dev/null +++ b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.c @@ -0,0 +1,4381 @@ +/** @file
+ This driver manages user information and produces user manager protocol.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
+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"
+
+//
+// Guid used in user profile saving and in form browser.
+//
+EFI_GUID mUserManagerGuid = USER_IDENTIFY_MANAGER_GUID;
+
+//
+// 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)
+ }
+ },
+ //
+ // {ACA7C06F-743C-454f-9C6D-692138482498}
+ //
+ { 0xaca7c06f, 0x743c, 0x454f, { 0x9c, 0x6d, 0x69, 0x21, 0x38, 0x48, 0x24, 0x98 } }
+ },
+ {
+ 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;
+}
+
+/**
+ Find the credential provider in the specified identity policy.
+
+ @param[in] FindIdentity Point to the user identity policy.
+ @param[in] IdentifyInfo Point to the user information to be searched.
+
+ @retval TRUE The credential provider was found in the identity policy.
+ @retval FALSE The credential provider was not found.
+**/
+BOOLEAN
+FindProvider (
+ IN EFI_USER_INFO_IDENTITY_POLICY *FindIdentity,
+ IN CONST EFI_USER_INFO *IdentifyInfo
+ )
+{
+ UINTN TotalLen;
+ EFI_USER_INFO_IDENTITY_POLICY *Identity;
+
+ //
+ // Found the credential provider.
+ //
+ TotalLen = 0;
+ while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) {
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen);
+ if ((Identity->Type == FindIdentity->Type) &&
+ (Identity->Length == FindIdentity->Length) &&
+ CompareGuid ((EFI_GUID *) (Identity + 1), (EFI_GUID *) (FindIdentity + 1))
+ ) {
+ return TRUE;
+ }
+
+ TotalLen += Identity->Length;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ 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;
+}
+
+
+/**
+ Add or delete the user's credential record in the provider.
+
+ @param[in] ProviderGuid Point to credential provider guid or class guid.
+ @param[in] ByType If TRUE, Provider is credential class guid.
+ If FALSE, Provider is provider guid.
+ @param[in] User Points to user profile.
+
+ @retval EFI_SUCCESS Add or delete record successfully.
+ @retval Others Fail to add or delete record.
+
+**/
+EFI_STATUS
+ModifyProviderCredential (
+ IN EFI_GUID *Provider,
+ IN BOOLEAN ByType,
+ IN USER_PROFILE_ENTRY *User
+ )
+{
+ UINTN Index;
+ EFI_USER_CREDENTIAL_PROTOCOL *UserCredential;
+
+ if (Provider == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+
+ //
+ // Find the specified credential provider.
+ //
+ for (Index = 0; Index < mProviderDb->Count; Index++) {
+ //
+ // Check credential provider ID.
+ //
+ UserCredential = mProviderDb->Provider[Index];
+ if (CompareGuid (&UserCredential->Identifier, Provider)) {
+ return UserCredential->Enroll (UserCredential, User);
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Modify user's credential record in the providers.
+
+ Found the providers information in PolicyInfo, and then add or delete the user's credential
+ record in the providers.
+
+ @param User Points to user profile.
+ @param PolicyInfo Point to identification policy to be modified.
+ @param InfoLen The length of PolicyInfo.
+
+ @retval EFI_SUCCESS Modify PolicyInfo successfully.
+ @retval Others Fail to modify PolicyInfo.
+
+**/
+EFI_STATUS
+ModifyCredentialInfo (
+ IN USER_PROFILE_ENTRY *User,
+ IN UINT8 *PolicyInfo,
+ IN UINTN InfoLen
+ )
+{
+ EFI_STATUS Status;
+ UINTN TotalLen;
+ EFI_USER_INFO_IDENTITY_POLICY *Identity;
+
+ //
+ // Modify user's credential.
+ //
+ TotalLen = 0;
+ while (TotalLen < InfoLen) {
+ //
+ // Check identification policy according to type.
+ //
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) (PolicyInfo + TotalLen);
+ switch (Identity->Type) {
+ case EFI_USER_INFO_IDENTITY_CREDENTIAL_TYPE:
+ Status = ModifyProviderCredential ((EFI_GUID *) (Identity + 1), TRUE, User);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ break;
+
+ case EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER:
+ Status = ModifyProviderCredential ((EFI_GUID *) (Identity + 1), FALSE, User);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ TotalLen += Identity->Length;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ 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,
+ &mUserManagerGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ Delete ? 0 : User->UserProfileSize,
+ User->ProfileInfo
+ );
+ return Status;
+}
+
+
+/**
+ Replace the old identity info with NewInfo in NV Flash.
+
+ This function only replace the identity record in the user profile. Don't update
+ the the information on the credential provider.
+
+ @param[in] User Point to the user profile.
+ @param[in] NewInfo Point to the new identity policy info.
+ @param[out] UserInfo Point to the new added identity info.
+
+ @retval EFI_SUCCESS Replace user identity successfully.
+ @retval Others Fail to Replace user identity.
+
+**/
+EFI_STATUS
+SaveUserIpInfo (
+ IN USER_PROFILE_ENTRY * User,
+ IN CONST EFI_USER_INFO * NewInfo,
+ OUT EFI_USER_INFO **UserInfo OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO *OldIpInfo;
+ UINTN Offset;
+ UINTN NextOffset;
+
+ if ((NewInfo == NULL) || (User == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get user old identify policy information.
+ //
+ OldIpInfo = NULL;
+ Status = FindUserInfoByType (User, &OldIpInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the old identity policy offset.
+ //
+ Status = FindUserInfo (User, &OldIpInfo, FALSE, &Offset);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Delete the old identity policy information.
+ //
+ NextOffset = ALIGN_VARIABLE (OldIpInfo->InfoSize) + Offset;
+ User->UserProfileSize -= ALIGN_VARIABLE (OldIpInfo->InfoSize);
+ if (Offset < User->UserProfileSize) {
+ CopyMem (User->ProfileInfo + Offset, User->ProfileInfo + NextOffset, User->UserProfileSize - Offset);
+ }
+
+ //
+ // Add new user information.
+ //
+ if (User->MaxProfileSize - User->UserProfileSize < ALIGN_VARIABLE (NewInfo->InfoSize)) {
+ if (!ExpandUserProfile (User, ALIGN_VARIABLE (NewInfo->InfoSize))) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ CopyMem (User->ProfileInfo + User->UserProfileSize, (VOID *) NewInfo, NewInfo->InfoSize);
+ if (UserInfo != NULL) {
+ *UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + User->UserProfileSize);
+ }
+
+ User->UserProfileSize += ALIGN_VARIABLE (NewInfo->InfoSize);
+
+ //
+ // Save user profile information.
+ //
+ Status = SaveNvUserProfile (User, FALSE);
+ return Status;
+}
+
+
+/**
+ Remove the provider in FindIdentity from the user identification information record.
+
+ @param[in, out] NewInfo On entry, points to the user information to remove provider.
+ On return, points to the user information the provider is removed.
+ @param[in] FindIdentity Point to the user identity policy.
+
+ @retval TRUE The provider is removed successfully.
+ @retval FALSE Fail to remove the provider.
+
+**/
+BOOLEAN
+RemoveProvider (
+ IN OUT EFI_USER_INFO **NewInfo,
+ IN EFI_USER_INFO_IDENTITY_POLICY *FindIdentity
+ )
+{
+ UINTN TotalLen;
+ EFI_USER_INFO_IDENTITY_POLICY *Identity;
+ EFI_USER_INFO *IdentifyInfo;
+ UINT8 *Buffer;
+
+ IdentifyInfo = *NewInfo;
+ TotalLen = IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO);
+ if (TotalLen == FindIdentity->Length) {
+ //
+ // Only one credential provider in the identification policy.
+ // Set the new policy to be TRUE after removed the provider.
+ //
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) (IdentifyInfo + 1);
+ Identity->Type = EFI_USER_INFO_IDENTITY_TRUE;
+ Identity->Length = sizeof (EFI_USER_INFO_IDENTITY_POLICY);
+ IdentifyInfo->InfoSize = sizeof (EFI_USER_INFO) + Identity->Length;
+ return TRUE;
+ }
+
+ //
+ // Found the credential provider.
+ //
+ TotalLen = 0;
+ while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) {
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen);
+ if ((Identity->Type == FindIdentity->Type) &&
+ (Identity->Length == FindIdentity->Length) &&
+ CompareGuid ((EFI_GUID *) (Identity + 1), (EFI_GUID *) (FindIdentity + 1))
+ ) {
+ //
+ // Found the credential provider to delete
+ //
+ if (Identity == (EFI_USER_INFO_IDENTITY_POLICY *)(IdentifyInfo + 1)) {
+ //
+ // It is the first item in the identification policy, delete it and the connector after it.
+ //
+ Buffer = (UINT8 *) Identity + Identity->Length + sizeof(EFI_USER_INFO_IDENTITY_POLICY);
+ IdentifyInfo->InfoSize -= Identity->Length + sizeof(EFI_USER_INFO_IDENTITY_POLICY);
+ TotalLen = IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO);
+ CopyMem (Identity, Buffer, TotalLen);
+ } else {
+ //
+ // It is not the first item in the identification policy, delete it and the connector before it.
+ //
+ Buffer = (UINT8 *) Identity + Identity->Length;
+ TotalLen = IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO);
+ TotalLen -= (Buffer - (UINT8 *)(IdentifyInfo + 1));
+ IdentifyInfo->InfoSize -= Identity->Length + sizeof(EFI_USER_INFO_IDENTITY_POLICY);
+ CopyMem ((UINT8 *) (Identity - 1), Buffer, TotalLen);
+ }
+ return TRUE;
+ }
+
+ TotalLen += Identity->Length;
+ }
+ return FALSE;
+}
+
+
+/**
+ This function replaces the old identity policy with a new identity policy.
+
+ This function changes user identity policy information.
+ If enroll new credential failed, recover the old identity policy.
+
+ For new policy:
+ a. For each credential, if it is newly added, try to enroll it.
+ If enroll failed, try to delete the newly added ones.
+
+ b. For each credential, if it exists in the old policy, delete old one,
+ and enroll new one. If failed to enroll the new one, removed it from new
+ identification policy.
+
+ For old policy:
+ a. For each credential, if it does not exist in new one, delete it.
+
+ @param[in] User Point to the user profile.
+ @param[in] Info Points to the user identity information.
+ @param[in] InfoSize The size of Info (Not used in this function).
+ @param[out] IpInfo The new identification info after modify.
+
+ @retval EFI_SUCCESS Modify user identity policy successfully.
+ @retval Others Fail to modify user identity policy.
+
+**/
+EFI_STATUS
+ModifyUserIpInfo (
+ IN USER_PROFILE_ENTRY *User,
+ IN CONST EFI_USER_INFO *Info,
+ IN UINTN InfoSize,
+ OUT EFI_USER_INFO **IpInfo
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO *OldIpInfo;
+ UINTN TotalLen;
+ EFI_USER_INFO_IDENTITY_POLICY *Identity;
+ UINT32 CredentialCount;
+ EFI_USER_INFO *NewIpInfo;
+
+ //
+ // Get user old identify policy information.
+ //
+ OldIpInfo = NULL;
+ Status = FindUserInfoByType (User, &OldIpInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ASSERT (OldIpInfo != NULL);
+
+ //
+ // Enroll new added credential provider.
+ //
+ CredentialCount = 0;
+ TotalLen = 0;
+ while (TotalLen < Info->InfoSize - sizeof (EFI_USER_INFO)) {
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (Info + 1) + TotalLen);
+ if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) {
+ if (!FindProvider (Identity, OldIpInfo)) {
+ //
+ // The credential is NOT found in the old identity policy; add it.
+ //
+ Status = ModifyCredentialInfo (User, (UINT8 *) Identity, Identity->Length);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ CredentialCount++;
+ }
+ }
+
+ TotalLen += Identity->Length;
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Enroll new credential failed. Delete the newly enrolled credential, and return.
+ //
+ TotalLen = 0;
+ while (TotalLen < Info->InfoSize - sizeof (EFI_USER_INFO)) {
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (Info + 1) + TotalLen);
+ if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) {
+ if (!FindProvider (Identity, OldIpInfo)) {
+ //
+ // The credential is NOT found in the old identity policy. Delete it.
+ //
+ if (CredentialCount == 0) {
+ break;
+ }
+
+ ModifyCredentialInfo (User, (UINT8 *) Identity, Identity->Length);
+ CredentialCount--;
+ }
+ }
+ TotalLen += Identity->Length;
+ }
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Backup new identification policy
+ //
+ NewIpInfo = AllocateCopyPool (Info->InfoSize, Info);
+ ASSERT (NewIpInfo != NULL);
+
+ //
+ // Enroll the credential that existed in the old identity policy.
+ //
+ TotalLen = 0;
+ while (TotalLen < Info->InfoSize - sizeof (EFI_USER_INFO)) {
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (Info + 1) + TotalLen);
+ if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) {
+ if (FindProvider (Identity, OldIpInfo)) {
+ //
+ // The credential is found in the old identity policy, so delete the old credential first.
+ //
+ Status = ModifyCredentialInfo (User, (UINT8 *) Identity, Identity->Length);
+ if (EFI_ERROR (Status)) {
+ //
+ // Failed to delete old credential.
+ //
+ FreePool (NewIpInfo);
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Add the new credential.
+ //
+ Status = ModifyCredentialInfo (User, (UINT8 *) Identity, Identity->Length);
+ if (EFI_ERROR (Status)) {
+ //
+ // Failed to enroll the user by new identification policy.
+ // So removed the credential provider from the identification policy
+ //
+ RemoveProvider (&NewIpInfo, Identity);
+ }
+ }
+ }
+ TotalLen += Identity->Length;
+ }
+
+ //
+ // Delete old credential that didn't exist in the new identity policy.
+ //
+ TotalLen = 0;
+ while (TotalLen < OldIpInfo->InfoSize - sizeof (EFI_USER_INFO)) {
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (OldIpInfo + 1) + TotalLen);
+ if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) {
+ if (!FindProvider (Identity, Info)) {
+ //
+ // The credential is NOT found in the new identity policy. Delete the old credential.
+ //
+ ModifyCredentialInfo (User, (UINT8 *) Identity, Identity->Length);
+ }
+ }
+ TotalLen += Identity->Length;
+ }
+
+ *IpInfo = NewIpInfo;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ 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 credential.
+ //
+ if (((EFI_USER_INFO *) Info)->InfoType == EFI_USER_INFO_IDENTITY_POLICY_RECORD) {
+ Status = ModifyCredentialInfo (
+ User,
+ (UINT8 *) ((EFI_USER_INFO *) Info + 1),
+ InfoSize - sizeof (EFI_USER_INFO)
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // 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;
+ } else if (Info->InfoType == EFI_USER_INFO_IDENTITY_POLICY_RECORD) {
+ Status = ModifyCredentialInfo (User, (UINT8 *) (Info + 1), Info->InfoSize - sizeof (EFI_USER_INFO));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // 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;
+ EFI_USER_INFO *IpInfo;
+
+ 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);
+ }
+
+ if (Info->InfoType == EFI_USER_INFO_IDENTITY_POLICY_RECORD) {
+ //
+ // For user identification policy, need to update the info in credential provider.
+ //
+ IpInfo = NULL;
+ Status = ModifyUserIpInfo (User, Info, InfoSize, &IpInfo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ASSERT (IpInfo != NULL);
+ Status = SaveUserIpInfo (User, IpInfo, UserInfo);
+ if (IpInfo->InfoSize != Info->InfoSize) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ FreePool (IpInfo);
+ return Status;
+ }
+
+ 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;
+ EFI_USER_INFO *UserInfo;
+
+ //
+ // 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 credential information.
+ //
+ UserInfo = NULL;
+ Status = FindUserInfoByType (User, &UserInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);
+ if (Status == EFI_SUCCESS) {
+ Status = DelUserInfo (User, UserInfo, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // 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 identifir 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_CREDENTIAL_PROTOCOL *UserCredential;
+ EFI_USER_INFO *IdInfo;
+
+ 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;
+ }
+
+ if (User == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get user ID information.
+ //
+ IdInfo = NULL;
+ Status = FindUserInfoByType (User, &IdInfo, EFI_USER_INFO_IDENTIFIER_RECORD);
+ ASSERT (IdInfo != NULL);
+
+ if (CompareMem ((UINT8 *) (IdInfo + 1), UserId, sizeof (EFI_USER_INFO_IDENTIFIER)) != 0) {
+ //
+ // One user name is selected, but the other's credential is given. Here no user passed.
+ //
+ break;
+ }
+ 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_CREDENTIAL_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
+ &mUserManagerGuid, // 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
+ &mUserManagerGuid, // 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_CHANGING:
+ {
+ 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;
+ }
+
+ //
+ // QuestionId comes from the first Form (Select a user to identify).
+ //
+ 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;
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ }
+ }
+ 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, &mUserManagerGuid, &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, &mUserManagerGuid, &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, &mUserManagerGuid, 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, &mUserManagerGuid, 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, &mUserManagerGuid, 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,
+ &gEfiUserCredentialProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuf
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get provider infomation.
+ //
+ mProviderDb = AllocateZeroPool (
+ sizeof (CREDENTIAL_PROVIDER_INFO) -
+ sizeof (EFI_USER_CREDENTIAL_PROTOCOL *) +
+ HandleCount * sizeof (EFI_USER_CREDENTIAL_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],
+ &gEfiUserCredentialProtocolGuid,
+ (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 <ConfigRequest> 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 <ConfigAltResp> 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 <ConfigResp> 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 (
+ &mUserManagerGuid,
+ 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_CREDENTIAL_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,
+ &mUserManagerGuid,
+ 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_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 while deselected.
+ If the User Identity Manager doesn't support asynchronous changes in credentials, then this function
+ should return EFI_UNSUPPORTED.
+ If the User Identity Manager supports this, it will call User() to get the user identifier and then
+ GetNextInfo() and GetInfo() in the User Credential Protocol to get all of the information from the
+ credential and add it.
+
+ @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_CREDENTIAL_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
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_CREDENTIAL_PROTOCOL *Provider;
+ EFI_USER_INFO_IDENTIFIER UserId;
+ EFI_USER_INFO_HANDLE UserInfo;
+ EFI_USER_INFO_HANDLE UserInfo2;
+ UINTN InfoSize;
+ EFI_USER_INFO *Info;
+ USER_PROFILE_ENTRY *User;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = gBS->HandleProtocol (
+ Changed,
+ &gEfiUserCredentialProtocolGuid,
+ (VOID **) &Provider
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Provider->User (Provider, NULL, &UserId);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Find user with the UserId.
+ //
+ User = NULL;
+ while (TRUE) {
+ //
+ // Find next user profile.
+ //
+ Status = FindUserProfile (&User, TRUE, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Find the user information.
+ //
+ Info = NULL;
+ FindUserInfoByType (User, &Info, EFI_USER_INFO_IDENTIFIER_RECORD);
+ if (CompareMem ((UINT8 *) (Info + 1), UserId, sizeof (UserId)) == 0) {
+ //
+ // Found the infomation record.
+ //
+ break;
+ }
+ }
+
+ UserInfo = NULL;
+ do {
+ //
+ // Get user info handle.
+ //
+ Status = Provider->GetNextInfo(Provider, &UserInfo);
+ if (EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get the user information from the user info handle.
+ //
+ InfoSize = 0;
+ Status = Provider->GetInfo(Provider, UserInfo, NULL, &InfoSize);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Info = AllocateZeroPool (InfoSize);
+ if (Info == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = Provider->GetInfo(Provider, UserInfo, Info, &InfoSize);
+ if (EFI_ERROR (Status)) {
+ FreePool (Info);
+ break;
+ }
+ }
+ break;
+ }
+
+ //
+ // Save the user information.
+ //
+ UserInfo2 = NULL;
+ Status = UserProfileSetInfo (&gUserIdentifyManager, (EFI_USER_PROFILE_HANDLE)User, &UserInfo2, Info, InfoSize);
+ FreePool (Info);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ } while (TRUE);
+
+ return Status;
+}
+
+
+/**
+ 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;
+
+ //
+ // 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;
+}
+
+
|