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