ArmPkg/ArmMmuLib ARM: fix thinko in second level page table handling
[mirror_edk2.git] / SecurityPkg / UserIdentification / UserIdentifyManagerDxe / UserIdentifyManager.c
1 /** @file\r
2   This driver manages user information and produces user manager protocol.\r
3 \r
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
5 (C) Copyright 2018 Hewlett Packard Enterprise Development LP<BR>\r
6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution.  The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10 \r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13 \r
14 **/\r
15 \r
16 #include "UserIdentifyManager.h"\r
17 \r
18 //\r
19 // Default user name.\r
20 //\r
21 CHAR16                      mUserName[]       = L"Administrator";\r
22 \r
23 //\r
24 // Points to the user profile database.\r
25 //\r
26 USER_PROFILE_DB             *mUserProfileDb   = NULL;\r
27 \r
28 //\r
29 // Points to the credential providers found in system.\r
30 //\r
31 CREDENTIAL_PROVIDER_INFO    *mProviderDb      = NULL;\r
32 \r
33 //\r
34 // Current user shared in multi function.\r
35 //\r
36 EFI_USER_PROFILE_HANDLE     mCurrentUser      = NULL;\r
37 \r
38 //\r
39 // Flag indicates a user is identified.\r
40 //\r
41 BOOLEAN                     mIdentified       = FALSE;\r
42 USER_MANAGER_CALLBACK_INFO  *mCallbackInfo    = NULL;\r
43 HII_VENDOR_DEVICE_PATH      mHiiVendorDevicePath = {\r
44   {\r
45     {\r
46       HARDWARE_DEVICE_PATH,\r
47       HW_VENDOR_DP,\r
48       {\r
49         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),\r
50         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)\r
51       }\r
52     },\r
53     USER_IDENTIFY_MANAGER_GUID\r
54   },\r
55   {\r
56     END_DEVICE_PATH_TYPE,\r
57     END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
58     {\r
59       (UINT8) (END_DEVICE_PATH_LENGTH),\r
60       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)\r
61     }\r
62   }\r
63 };\r
64 \r
65 \r
66 EFI_USER_MANAGER_PROTOCOL gUserIdentifyManager = {\r
67   UserProfileCreate,\r
68   UserProfileDelete,\r
69   UserProfileGetNext,\r
70   UserProfileCurrent,\r
71   UserProfileIdentify,\r
72   UserProfileFind,\r
73   UserProfileNotify,\r
74   UserProfileGetInfo,\r
75   UserProfileSetInfo,\r
76   UserProfileDeleteInfo,\r
77   UserProfileGetNextInfo,\r
78 };\r
79 \r
80 \r
81 /**\r
82   Find the specified user in the user database.\r
83 \r
84   This function searches the specified user from the beginning of the user database.\r
85   And if NextUser is TRUE, return the next User in the user database.\r
86 \r
87   @param[in, out] User         On entry, points to the user profile entry to search.\r
88                                On return, points to the user profile entry or NULL if not found.\r
89   @param[in]      NextUser     If FALSE, find the user in user profile database specifyed by User\r
90                                If TRUE, find the next user in user profile database specifyed\r
91                                by User.\r
92   @param[out]     ProfileIndex A pointer to the index of user profile database that matches the\r
93                                user specifyed by User.\r
94 \r
95   @retval EFI_NOT_FOUND        User was NULL, or User was not found, or the next user was not found.\r
96   @retval EFI_SUCCESS          User or the next user are found in user profile database\r
97 \r
98 **/\r
99 EFI_STATUS\r
100 FindUserProfile (\r
101   IN OUT  USER_PROFILE_ENTRY                    **User,\r
102   IN      BOOLEAN                               NextUser,\r
103      OUT  UINTN                                 *ProfileIndex OPTIONAL\r
104   )\r
105 {\r
106   UINTN               Index;\r
107 \r
108   //\r
109   // Check parameters\r
110   //\r
111   if ((mUserProfileDb == NULL) || (User == NULL)) {\r
112     return EFI_NOT_FOUND;\r
113   }\r
114 \r
115   //\r
116   // Check whether the user profile is in the user profile database.\r
117   //\r
118   for (Index = 0; Index < mUserProfileDb->UserProfileNum; Index++) {\r
119     if (mUserProfileDb->UserProfile[Index] == *User) {\r
120       if (ProfileIndex != NULL) {\r
121         *ProfileIndex = Index;\r
122       }\r
123       break;\r
124     }\r
125   }\r
126 \r
127   if (NextUser) {\r
128     //\r
129     // Find the next user profile.\r
130     //\r
131     Index++;\r
132     if (Index < mUserProfileDb->UserProfileNum) {\r
133       *User = mUserProfileDb->UserProfile[Index];\r
134     } else if (Index == mUserProfileDb->UserProfileNum) {\r
135       *User = NULL;\r
136       return EFI_NOT_FOUND;\r
137     } else {\r
138       if ((mUserProfileDb->UserProfileNum > 0) && (*User == NULL)) {\r
139         *User = mUserProfileDb->UserProfile[0];\r
140       } else {\r
141         *User = NULL;\r
142         return EFI_NOT_FOUND;\r
143       }\r
144     }\r
145   } else if (Index == mUserProfileDb->UserProfileNum) {\r
146     return EFI_NOT_FOUND;\r
147   }\r
148 \r
149   return EFI_SUCCESS;\r
150 }\r
151 \r
152 /**\r
153   Find the specified user information record in the specified User profile.\r
154 \r
155   This function searches the specified user information record from the beginning of the user\r
156   profile. And if NextInfo is TRUE, return the next info in the user profile.\r
157 \r
158   @param[in]      User     Points to the user profile entry.\r
159   @param[in, out] Info     On entry, points to the user information record or NULL to start\r
160                            searching with the first user information record.\r
161                            On return, points to the user information record or NULL if not found.\r
162   @param[in]      NextInfo If FALSE, find the user information record in profile specifyed by User.\r
163                            If TRUE, find the next user information record in profile specifyed\r
164                            by User.\r
165   @param[out]     Offset   A pointer to the offset of the information record in the user profile.\r
166 \r
167   @retval EFI_INVALID_PARAMETER Info is NULL\r
168   @retval EFI_NOT_FOUND         Info was not found, or the next Info was not found.\r
169   @retval EFI_SUCCESS           Info or the next info are found in user profile.\r
170 \r
171 **/\r
172 EFI_STATUS\r
173 FindUserInfo (\r
174   IN     USER_PROFILE_ENTRY                    * User,\r
175   IN OUT EFI_USER_INFO                         **Info,\r
176   IN     BOOLEAN                               NextInfo,\r
177      OUT UINTN                                 *Offset OPTIONAL\r
178   )\r
179 {\r
180   EFI_STATUS    Status;\r
181   EFI_USER_INFO *UserInfo;\r
182   UINTN         InfoLen;\r
183 \r
184   if (Info == NULL) {\r
185     return EFI_INVALID_PARAMETER;\r
186   }\r
187 \r
188   //\r
189   // Check user profile entry\r
190   //\r
191   Status = FindUserProfile (&User, FALSE, NULL);\r
192   if (EFI_ERROR (Status)) {\r
193     return Status;\r
194   }\r
195 \r
196   //\r
197   // Find user information in the specified user record.\r
198   //\r
199   InfoLen = 0;\r
200   while (InfoLen < User->UserProfileSize) {\r
201     UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + InfoLen);\r
202     if (UserInfo == *Info) {\r
203       if (Offset != NULL) {\r
204         *Offset = InfoLen;\r
205       }\r
206       break;\r
207     }\r
208     InfoLen += ALIGN_VARIABLE (UserInfo->InfoSize);\r
209   }\r
210 \r
211   //\r
212   // Check whether to find the next user information.\r
213   //\r
214   if (NextInfo) {\r
215     if (InfoLen < User->UserProfileSize) {\r
216       UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + InfoLen);\r
217       InfoLen += ALIGN_VARIABLE (UserInfo->InfoSize);\r
218       if (InfoLen < User->UserProfileSize) {\r
219         *Info = (EFI_USER_INFO *) (User->ProfileInfo + InfoLen);\r
220         if (Offset != NULL) {\r
221           *Offset = InfoLen;\r
222         }\r
223       } else if (InfoLen == User->UserProfileSize) {\r
224         *Info = NULL;\r
225         return EFI_NOT_FOUND;\r
226       }\r
227     } else {\r
228       if (*Info == NULL) {\r
229         *Info = (EFI_USER_INFO *) User->ProfileInfo;\r
230         if (Offset != NULL) {\r
231           *Offset = 0;\r
232         }\r
233       } else {\r
234         *Info = NULL;\r
235         return EFI_NOT_FOUND;\r
236       }\r
237     }\r
238   } else if (InfoLen == User->UserProfileSize) {\r
239     return EFI_NOT_FOUND;\r
240   }\r
241 \r
242   return EFI_SUCCESS;\r
243 }\r
244 \r
245 /**\r
246   Find a user infomation record by the information record type.\r
247 \r
248   This function searches all user information records of User. The search starts with the\r
249   user information record following Info and continues until either the information is found\r
250   or there are no more user infomation record.\r
251   A match occurs when a Info.InfoType field matches the user information record type.\r
252 \r
253   @param[in]      User     Points to the user profile record to search.\r
254   @param[in, out] Info     On entry, points to the user information record or NULL to start\r
255                            searching with the first user information record.\r
256                            On return, points to the user information record or NULL if not found.\r
257   @param[in]      InfoType The infomation type to be searched.\r
258 \r
259   @retval EFI_SUCCESS           User information was found. Info points to the user information record.\r
260   @retval EFI_NOT_FOUND         User information was not found.\r
261   @retval EFI_INVALID_PARAMETER User is NULL or Info is NULL.\r
262 \r
263 **/\r
264 EFI_STATUS\r
265 FindUserInfoByType (\r
266   IN      USER_PROFILE_ENTRY                    *User,\r
267   IN OUT  EFI_USER_INFO                         **Info,\r
268   IN      UINT8                                 InfoType\r
269   )\r
270 {\r
271   EFI_STATUS    Status;\r
272   EFI_USER_INFO *UserInfo;\r
273   UINTN         InfoLen;\r
274 \r
275   if (Info == NULL) {\r
276     return EFI_INVALID_PARAMETER;\r
277   }\r
278 \r
279   //\r
280   // Check whether the user has the specified user information.\r
281   //\r
282   InfoLen = 0;\r
283   if (*Info == NULL) {\r
284     Status = FindUserProfile (&User, FALSE, NULL);\r
285   } else {\r
286     Status = FindUserInfo (User, Info, TRUE, &InfoLen);\r
287   }\r
288 \r
289   if (EFI_ERROR (Status)) {\r
290     return EFI_NOT_FOUND;\r
291   }\r
292 \r
293   while (InfoLen < User->UserProfileSize) {\r
294     UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + InfoLen);\r
295     if (UserInfo->InfoType == InfoType) {\r
296       if (UserInfo != *Info) {\r
297         *Info = UserInfo;\r
298         return EFI_SUCCESS;\r
299       }\r
300     }\r
301 \r
302     InfoLen += ALIGN_VARIABLE (UserInfo->InfoSize);\r
303   }\r
304 \r
305   *Info = NULL;\r
306   return EFI_NOT_FOUND;\r
307 }\r
308 \r
309 /**\r
310   Find a user using a user information record.\r
311 \r
312   This function searches all user profiles for the specified user information record. The\r
313   search starts with the user information record handle following UserInfo and continues\r
314   until either the information is found or there are no more user profiles.\r
315   A match occurs when the Info.InfoType field matches the user information record type and the\r
316   user information record data matches the portion of Info passed the EFI_USER_INFO header.\r
317 \r
318   @param[in, out] User     On entry, points to the previously returned user profile record,\r
319                            or NULL to start searching with the first user profile.\r
320                            On return, points to the user profile entry, or NULL if not found.\r
321   @param[in, out] UserInfo On entry, points to the previously returned user information record,\r
322                            or NULL to start searching with the first.\r
323                            On return, points to the user information record, or NULL if not found.\r
324   @param[in]      Info     Points to the buffer containing the user information to be compared\r
325                            to the user information record.\r
326   @param[in]      InfoSize The size of Info, in bytes. Same as Info->InfoSize.\r
327 \r
328   @retval EFI_SUCCESS           User information was found. User points to the user profile record,\r
329                                 and UserInfo points to the user information record.\r
330   @retval EFI_NOT_FOUND         User information was not found.\r
331   @retval EFI_INVALID_PARAMETER User is NULL; Info is NULL; or, InfoSize is too small.\r
332 \r
333 **/\r
334 EFI_STATUS\r
335 FindUserProfileByInfo (\r
336   IN OUT  USER_PROFILE_ENTRY                    **User,\r
337   IN OUT  EFI_USER_INFO                         **UserInfo, OPTIONAL\r
338   IN      EFI_USER_INFO                         *Info,\r
339   IN      UINTN                                 InfoSize\r
340   )\r
341 {\r
342   EFI_STATUS    Status;\r
343   EFI_USER_INFO *InfoEntry;\r
344 \r
345 \r
346   if ((User == NULL) || (Info == NULL)) {\r
347     return EFI_INVALID_PARAMETER;\r
348   }\r
349 \r
350   if (InfoSize < sizeof (EFI_USER_INFO)) {\r
351     return EFI_INVALID_PARAMETER;\r
352   }\r
353 \r
354   if (UserInfo != NULL) {\r
355     InfoEntry = *UserInfo;\r
356   } else {\r
357     InfoEntry = NULL;\r
358   }\r
359   //\r
360   // Find user profile according to information.\r
361   //\r
362   if (*User == NULL) {\r
363     *User = mUserProfileDb->UserProfile[0];\r
364   }\r
365 \r
366   //\r
367   // Check user profile handle.\r
368   //\r
369   Status = FindUserProfile (User, FALSE, NULL);\r
370 \r
371   while (!EFI_ERROR (Status)) {\r
372     //\r
373     // Find the user information in a user profile.\r
374     //\r
375     while (TRUE) {\r
376       Status = FindUserInfoByType (*User, &InfoEntry, Info->InfoType);\r
377       if (EFI_ERROR (Status)) {\r
378         break;\r
379       }\r
380 \r
381       if (InfoSize == Info->InfoSize) {\r
382         if (CompareMem ((UINT8 *) (InfoEntry + 1), (UINT8 *) (Info + 1), InfoSize - sizeof (EFI_USER_INFO)) == 0) {\r
383           //\r
384           // Found the infomation record.\r
385           //\r
386           if (UserInfo != NULL) {\r
387             *UserInfo = InfoEntry;\r
388           }\r
389           return EFI_SUCCESS;\r
390         }\r
391       }\r
392     }\r
393 \r
394     //\r
395     // Get next user profile.\r
396     //\r
397     InfoEntry = NULL;\r
398     Status    = FindUserProfile (User, TRUE, NULL);\r
399   }\r
400 \r
401   return EFI_NOT_FOUND;\r
402 }\r
403 \r
404 \r
405 /**\r
406   Check whether the access policy is valid.\r
407 \r
408   @param[in]  PolicyInfo          Point to the access policy.\r
409   @param[in]  InfoLen             The policy length.\r
410 \r
411   @retval TRUE     The policy is a valid access policy.\r
412   @retval FALSE    The access policy is not a valid access policy.\r
413 \r
414 **/\r
415 BOOLEAN\r
416 CheckAccessPolicy (\r
417   IN  UINT8                                     *PolicyInfo,\r
418   IN  UINTN                                     InfoLen\r
419   )\r
420 {\r
421   UINTN                         TotalLen;\r
422   UINTN                         ValueLen;\r
423   UINTN                         OffSet;\r
424   EFI_USER_INFO_ACCESS_CONTROL  Access;\r
425   EFI_DEVICE_PATH_PROTOCOL      *Path;\r
426   UINTN                         PathSize;\r
427 \r
428   TotalLen = 0;\r
429   while (TotalLen < InfoLen) {\r
430     //\r
431     // Check access policy according to type.\r
432     //\r
433     CopyMem (&Access, PolicyInfo + TotalLen, sizeof (Access));\r
434     ValueLen = Access.Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL);\r
435     switch (Access.Type) {\r
436     case EFI_USER_INFO_ACCESS_FORBID_LOAD:\r
437     case EFI_USER_INFO_ACCESS_PERMIT_LOAD:\r
438     case EFI_USER_INFO_ACCESS_FORBID_CONNECT:\r
439     case EFI_USER_INFO_ACCESS_PERMIT_CONNECT:\r
440       OffSet = 0;\r
441       while (OffSet < ValueLen) {\r
442         Path      = (EFI_DEVICE_PATH_PROTOCOL *) (PolicyInfo + TotalLen + sizeof (Access) + OffSet);\r
443         PathSize  = GetDevicePathSize (Path);\r
444         OffSet += PathSize;\r
445       }\r
446       if (OffSet != ValueLen) {\r
447         return FALSE;\r
448       }\r
449       break;\r
450 \r
451     case EFI_USER_INFO_ACCESS_SETUP:\r
452       if (ValueLen % sizeof (EFI_GUID) != 0) {\r
453         return FALSE;\r
454       }\r
455       break;\r
456 \r
457     case EFI_USER_INFO_ACCESS_BOOT_ORDER:\r
458       if (ValueLen % sizeof (EFI_USER_INFO_ACCESS_BOOT_ORDER_HDR) != 0) {\r
459         return FALSE;\r
460       }\r
461       break;\r
462 \r
463     case EFI_USER_INFO_ACCESS_ENROLL_SELF:\r
464     case EFI_USER_INFO_ACCESS_ENROLL_OTHERS:\r
465     case EFI_USER_INFO_ACCESS_MANAGE:\r
466       if (ValueLen != 0) {\r
467         return FALSE;\r
468       }\r
469       break;\r
470 \r
471     default:\r
472       return FALSE;\r
473       break;\r
474     }\r
475 \r
476     TotalLen += Access.Size;\r
477   }\r
478 \r
479   if (TotalLen != InfoLen) {\r
480     return FALSE;\r
481   }\r
482 \r
483   return TRUE;\r
484 }\r
485 \r
486 \r
487 /**\r
488   Check whether the identity policy is valid.\r
489 \r
490   @param[in]  PolicyInfo          Point to the identity policy.\r
491   @param[in]  InfoLen             The policy length.\r
492 \r
493   @retval TRUE     The policy is a valid identity policy.\r
494   @retval FALSE    The access policy is not a valid identity policy.\r
495 \r
496 **/\r
497 BOOLEAN\r
498 CheckIdentityPolicy (\r
499   IN  UINT8                                     *PolicyInfo,\r
500   IN  UINTN                                     InfoLen\r
501   )\r
502 {\r
503   UINTN                         TotalLen;\r
504   UINTN                         ValueLen;\r
505   EFI_USER_INFO_IDENTITY_POLICY *Identity;\r
506 \r
507   TotalLen  = 0;\r
508 \r
509   //\r
510   // Check each part of policy expression.\r
511   //\r
512   while (TotalLen < InfoLen) {\r
513     //\r
514     // Check access polisy according to type.\r
515     //\r
516     Identity  = (EFI_USER_INFO_IDENTITY_POLICY *) (PolicyInfo + TotalLen);\r
517     ValueLen  = Identity->Length - sizeof (EFI_USER_INFO_IDENTITY_POLICY);\r
518     switch (Identity->Type) {\r
519     //\r
520     // Check False option.\r
521     //\r
522     case EFI_USER_INFO_IDENTITY_FALSE:\r
523       if (ValueLen != 0) {\r
524         return FALSE;\r
525       }\r
526       break;\r
527 \r
528     //\r
529     // Check True option.\r
530     //\r
531     case EFI_USER_INFO_IDENTITY_TRUE:\r
532       if (ValueLen != 0) {\r
533         return FALSE;\r
534       }\r
535       break;\r
536 \r
537     //\r
538     // Check negative operation.\r
539     //\r
540     case EFI_USER_INFO_IDENTITY_NOT:\r
541       if (ValueLen != 0) {\r
542         return FALSE;\r
543       }\r
544       break;\r
545 \r
546     //\r
547     // Check and operation.\r
548     //\r
549     case EFI_USER_INFO_IDENTITY_AND:\r
550       if (ValueLen != 0) {\r
551         return FALSE;\r
552       }\r
553       break;\r
554 \r
555     //\r
556     // Check or operation.\r
557     //\r
558     case EFI_USER_INFO_IDENTITY_OR:\r
559       if (ValueLen != 0) {\r
560         return FALSE;\r
561       }\r
562       break;\r
563 \r
564     //\r
565     // Check credential provider by type.\r
566     //\r
567     case EFI_USER_INFO_IDENTITY_CREDENTIAL_TYPE:\r
568       if (ValueLen != sizeof (EFI_GUID)) {\r
569         return FALSE;\r
570       }\r
571       break;\r
572 \r
573     //\r
574     // Check credential provider by ID.\r
575     //\r
576     case EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER:\r
577       if (ValueLen != sizeof (EFI_GUID)) {\r
578         return FALSE;\r
579       }\r
580       break;\r
581 \r
582     default:\r
583       return FALSE;\r
584       break;\r
585     }\r
586 \r
587     TotalLen += Identity->Length;\r
588   }\r
589 \r
590   if (TotalLen != InfoLen) {\r
591     return FALSE;\r
592   }\r
593 \r
594   return TRUE;\r
595 }\r
596 \r
597 \r
598 /**\r
599   Check whether the user information is a valid user information record.\r
600 \r
601   @param[in]  Info points to the user information.\r
602 \r
603   @retval TRUE     The info is a valid user information record.\r
604   @retval FALSE    The info is not a valid user information record.\r
605 \r
606 **/\r
607 BOOLEAN\r
608 CheckUserInfo (\r
609   IN CONST  EFI_USER_INFO                       *Info\r
610   )\r
611 {\r
612   UINTN       InfoLen;\r
613 \r
614   if (Info == NULL) {\r
615     return FALSE;\r
616   }\r
617   //\r
618   // Check user information according to information type.\r
619   //\r
620   InfoLen = Info->InfoSize - sizeof (EFI_USER_INFO);\r
621   switch (Info->InfoType) {\r
622   case EFI_USER_INFO_EMPTY_RECORD:\r
623     if (InfoLen != 0) {\r
624       return FALSE;\r
625     }\r
626     break;\r
627 \r
628   case EFI_USER_INFO_NAME_RECORD:\r
629   case EFI_USER_INFO_CREDENTIAL_TYPE_NAME_RECORD:\r
630   case EFI_USER_INFO_CREDENTIAL_PROVIDER_NAME_RECORD:\r
631     break;\r
632 \r
633   case EFI_USER_INFO_CREATE_DATE_RECORD:\r
634   case EFI_USER_INFO_USAGE_DATE_RECORD:\r
635     if (InfoLen != sizeof (EFI_TIME)) {\r
636       return FALSE;\r
637     }\r
638     break;\r
639 \r
640   case EFI_USER_INFO_USAGE_COUNT_RECORD:\r
641     if (InfoLen != sizeof (UINT64)) {\r
642       return FALSE;\r
643     }\r
644     break;\r
645 \r
646   case EFI_USER_INFO_IDENTIFIER_RECORD:\r
647     if (InfoLen != 16) {\r
648       return FALSE;\r
649     }\r
650     break;\r
651 \r
652   case EFI_USER_INFO_CREDENTIAL_TYPE_RECORD:\r
653   case EFI_USER_INFO_CREDENTIAL_PROVIDER_RECORD:\r
654   case EFI_USER_INFO_GUID_RECORD:\r
655     if (InfoLen != sizeof (EFI_GUID)) {\r
656       return FALSE;\r
657     }\r
658     break;\r
659 \r
660   case EFI_USER_INFO_PKCS11_RECORD:\r
661   case EFI_USER_INFO_CBEFF_RECORD:\r
662     break;\r
663 \r
664   case EFI_USER_INFO_FAR_RECORD:\r
665   case EFI_USER_INFO_RETRY_RECORD:\r
666     if (InfoLen != 1) {\r
667       return FALSE;\r
668     }\r
669     break;\r
670 \r
671   case EFI_USER_INFO_ACCESS_POLICY_RECORD:\r
672     if(!CheckAccessPolicy ((UINT8 *) (Info + 1), InfoLen)) {\r
673       return FALSE;\r
674     }\r
675     break;\r
676 \r
677   case EFI_USER_INFO_IDENTITY_POLICY_RECORD:\r
678     if (!CheckIdentityPolicy ((UINT8 *) (Info + 1), InfoLen)) {\r
679       return FALSE;\r
680     }\r
681     break;\r
682 \r
683   default:\r
684     return FALSE;\r
685     break;\r
686   }\r
687 \r
688   return TRUE;\r
689 }\r
690 \r
691 \r
692 /**\r
693   Check the user profile data format to be added.\r
694 \r
695   @param[in]  UserProfileInfo     Points to the user profile data.\r
696   @param[in]  UserProfileSize     The length of user profile data.\r
697 \r
698   @retval TRUE     It is a valid user profile.\r
699   @retval FALSE    It is not a valid user profile.\r
700 \r
701 **/\r
702 BOOLEAN\r
703 CheckProfileInfo (\r
704   IN  UINT8                                     *UserProfileInfo,\r
705   IN  UINTN                                     UserProfileSize\r
706   )\r
707 {\r
708   UINTN         ChkLen;\r
709   EFI_USER_INFO *Info;\r
710 \r
711   if (UserProfileInfo == NULL) {\r
712     return FALSE;\r
713   }\r
714 \r
715   //\r
716   // Check user profile information length.\r
717   //\r
718   ChkLen = 0;\r
719   while (ChkLen < UserProfileSize) {\r
720     Info = (EFI_USER_INFO *) (UserProfileInfo + ChkLen);\r
721     //\r
722     // Check user information format.\r
723     //\r
724     if (!CheckUserInfo (Info)) {\r
725       return FALSE;\r
726     }\r
727 \r
728     ChkLen += ALIGN_VARIABLE (Info->InfoSize);\r
729   }\r
730 \r
731   if (ChkLen != UserProfileSize) {\r
732     return FALSE;\r
733   }\r
734 \r
735   return TRUE;\r
736 }\r
737 \r
738 \r
739 /**\r
740   Find the specified RightType in current user profile.\r
741 \r
742   @param[in]  RightType      Could be EFI_USER_INFO_ACCESS_MANAGE,\r
743                              EFI_USER_INFO_ACCESS_ENROLL_OTHERS or\r
744                              EFI_USER_INFO_ACCESS_ENROLL_SELF.\r
745 \r
746   @retval TRUE     Find the specified RightType in current user profile.\r
747   @retval FALSE    Can't find the right in the profile.\r
748 \r
749 **/\r
750 BOOLEAN\r
751 CheckCurrentUserAccessRight (\r
752   IN        UINT32                              RightType\r
753   )\r
754 {\r
755   EFI_STATUS                    Status;\r
756   EFI_USER_INFO                 *Info;\r
757   UINTN                         TotalLen;\r
758   UINTN                         CheckLen;\r
759   EFI_USER_INFO_ACCESS_CONTROL  Access;\r
760 \r
761   //\r
762   // Get user access right information.\r
763   //\r
764   Info = NULL;\r
765   Status = FindUserInfoByType (\r
766             (USER_PROFILE_ENTRY *) mCurrentUser,\r
767             &Info,\r
768             EFI_USER_INFO_ACCESS_POLICY_RECORD\r
769             );\r
770   if (EFI_ERROR (Status)) {\r
771     return FALSE;\r
772   }\r
773 \r
774   ASSERT (Info != NULL);\r
775   TotalLen  = Info->InfoSize - sizeof (EFI_USER_INFO);\r
776   CheckLen  = 0;\r
777   while (CheckLen < TotalLen) {\r
778     //\r
779     // Check right according to access type.\r
780     //\r
781     CopyMem (&Access, (UINT8 *) (Info + 1) + CheckLen, sizeof (Access));\r
782     if (Access.Type == RightType) {\r
783       return TRUE;;\r
784     }\r
785 \r
786     CheckLen += Access.Size;\r
787   }\r
788 \r
789   return FALSE;\r
790 }\r
791 \r
792 \r
793 /**\r
794   Create a unique user identifier.\r
795 \r
796   @param[out]  Identifier     This points to the identifier.\r
797 \r
798 **/\r
799 VOID\r
800 GenerateIdentifier (\r
801    OUT    UINT8                               *Identifier\r
802   )\r
803 {\r
804   EFI_TIME  Time;\r
805   UINT64    MonotonicCount;\r
806   UINT32    *MonotonicPointer;\r
807   UINTN     Index;\r
808 \r
809   //\r
810   // Create a unique user identifier.\r
811   //\r
812   gRT->GetTime (&Time, NULL);\r
813   CopyMem (Identifier, &Time, sizeof (EFI_TIME));\r
814   //\r
815   // Remove zeros.\r
816   //\r
817   for (Index = 0; Index < sizeof (EFI_TIME); Index++) {\r
818     if (Identifier[Index] == 0) {\r
819       Identifier[Index] = 0x5a;\r
820     }\r
821   }\r
822 \r
823   MonotonicPointer = (UINT32 *) Identifier;\r
824   gBS->GetNextMonotonicCount (&MonotonicCount);\r
825   MonotonicPointer[0] += (UINT32) MonotonicCount;\r
826   MonotonicPointer[1] += (UINT32) MonotonicCount;\r
827   MonotonicPointer[2] += (UINT32) MonotonicCount;\r
828   MonotonicPointer[3] += (UINT32) MonotonicCount;\r
829 }\r
830 \r
831 \r
832 /**\r
833   Generate unique user ID.\r
834 \r
835   @param[out]  UserId                 Points to the user identifer.\r
836 \r
837 **/\r
838 VOID\r
839 GenerateUserId (\r
840   OUT    UINT8                               *UserId\r
841   )\r
842 {\r
843   EFI_STATUS              Status;\r
844   USER_PROFILE_ENTRY      *UserProfile;\r
845   EFI_USER_INFO           *UserInfo;\r
846   UINTN                   Index;\r
847 \r
848   //\r
849   // Generate unique user ID\r
850   //\r
851   while (TRUE) {\r
852     GenerateIdentifier (UserId);\r
853     //\r
854     // Check whether it's unique in user profile database.\r
855     //\r
856     if (mUserProfileDb == NULL) {\r
857       return ;\r
858     }\r
859 \r
860     for (Index = 0; Index < mUserProfileDb->UserProfileNum; Index++) {\r
861       UserProfile = (USER_PROFILE_ENTRY *) (mUserProfileDb->UserProfile[Index]);\r
862       UserInfo    = NULL;\r
863       Status      = FindUserInfoByType (UserProfile, &UserInfo, EFI_USER_INFO_IDENTIFIER_RECORD);\r
864       if (EFI_ERROR (Status)) {\r
865         continue;\r
866       }\r
867 \r
868       if (CompareMem ((UINT8 *) (UserInfo + 1), UserId, sizeof (EFI_USER_INFO_IDENTIFIER)) == 0) {\r
869         break;\r
870       }\r
871     }\r
872 \r
873     if (Index == mUserProfileDb->UserProfileNum) {\r
874       return ;\r
875     }\r
876   }\r
877 }\r
878 \r
879 \r
880 /**\r
881   Expand user profile database.\r
882 \r
883   @retval TRUE     Success to expand user profile database.\r
884   @retval FALSE    Fail to expand user profile database.\r
885 \r
886 **/\r
887 BOOLEAN\r
888 ExpandUsermUserProfileDb (\r
889   VOID\r
890   )\r
891 {\r
892   UINTN               MaxNum;\r
893   USER_PROFILE_DB     *NewDataBase;\r
894 \r
895   //\r
896   // Create new user profile database.\r
897   //\r
898   if (mUserProfileDb == NULL) {\r
899     MaxNum = USER_NUMBER_INC;\r
900   } else {\r
901     MaxNum = mUserProfileDb->MaxProfileNum + USER_NUMBER_INC;\r
902   }\r
903 \r
904   NewDataBase = AllocateZeroPool (\r
905                   sizeof (USER_PROFILE_DB) - sizeof (EFI_USER_PROFILE_HANDLE) +\r
906                   MaxNum * sizeof (EFI_USER_PROFILE_HANDLE)\r
907                   );\r
908   if (NewDataBase == NULL) {\r
909     return FALSE;\r
910   }\r
911 \r
912   NewDataBase->MaxProfileNum = MaxNum;\r
913 \r
914   //\r
915   // Copy old user profile database value\r
916   //\r
917   if (mUserProfileDb == NULL) {\r
918     NewDataBase->UserProfileNum = 0;\r
919   } else {\r
920     NewDataBase->UserProfileNum = mUserProfileDb->UserProfileNum;\r
921     CopyMem (\r
922       NewDataBase->UserProfile,\r
923       mUserProfileDb->UserProfile,\r
924       NewDataBase->UserProfileNum * sizeof (EFI_USER_PROFILE_HANDLE)\r
925       );\r
926     FreePool (mUserProfileDb);\r
927   }\r
928 \r
929   mUserProfileDb = NewDataBase;\r
930   return TRUE;\r
931 }\r
932 \r
933 \r
934 /**\r
935   Expand user profile\r
936 \r
937   @param[in]  User                    Points to user profile.\r
938   @param[in]  ExpandSize              The size of user profile.\r
939 \r
940   @retval TRUE     Success to expand user profile size.\r
941   @retval FALSE    Fail to expand user profile size.\r
942 \r
943 **/\r
944 BOOLEAN\r
945 ExpandUserProfile (\r
946   IN USER_PROFILE_ENTRY                         *User,\r
947   IN UINTN                                      ExpandSize\r
948   )\r
949 {\r
950   UINT8 *Info;\r
951   UINTN InfoSizeInc;\r
952 \r
953   //\r
954   // Allocate new memory.\r
955   //\r
956   InfoSizeInc = 128;\r
957   User->MaxProfileSize += ((ExpandSize + InfoSizeInc - 1) / InfoSizeInc) * InfoSizeInc;\r
958   Info = AllocateZeroPool (User->MaxProfileSize);\r
959   if (Info == NULL) {\r
960     return FALSE;\r
961   }\r
962 \r
963   //\r
964   // Copy exist information.\r
965   //\r
966   if (User->UserProfileSize > 0) {\r
967     CopyMem (Info, User->ProfileInfo, User->UserProfileSize);\r
968     FreePool (User->ProfileInfo);\r
969   }\r
970 \r
971   User->ProfileInfo = Info;\r
972   return TRUE;\r
973 }\r
974 \r
975 \r
976 /**\r
977   Save the user profile to non-volatile memory, or delete it from non-volatile memory.\r
978 \r
979   @param[in]  User         Point to the user profile\r
980   @param[in]  Delete       If TRUE, delete the found user profile.\r
981                            If FALSE, save the user profile.\r
982   @retval EFI_SUCCESS      Save or delete user profile successfully.\r
983   @retval Others           Fail to change the profile.\r
984 \r
985 **/\r
986 EFI_STATUS\r
987 SaveNvUserProfile (\r
988   IN  USER_PROFILE_ENTRY                        *User,\r
989   IN  BOOLEAN                                   Delete\r
990   )\r
991 {\r
992   EFI_STATUS  Status;\r
993 \r
994   //\r
995   // Check user profile entry.\r
996   //\r
997   Status = FindUserProfile (&User, FALSE, NULL);\r
998   if (EFI_ERROR (Status)) {\r
999     return Status;\r
1000   }\r
1001 \r
1002   //\r
1003   // Save the user profile to non-volatile memory.\r
1004   //\r
1005   Status = gRT->SetVariable (\r
1006                   User->UserVarName,\r
1007                   &gUserIdentifyManagerGuid,\r
1008                   EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
1009                   Delete ? 0 : User->UserProfileSize,\r
1010                   User->ProfileInfo\r
1011                   );\r
1012   return Status;\r
1013 }\r
1014 \r
1015 /**\r
1016   Add one new user info into the user's profile.\r
1017 \r
1018   @param[in]   User        point to the user profile\r
1019   @param[in]   Info        Points to the user information payload.\r
1020   @param[in]   InfoSize    The size of the user information payload, in bytes.\r
1021   @param[out]  UserInfo    Point to the new info in user profile\r
1022   @param[in]   Save        If TRUE, save the profile to NV flash.\r
1023                            If FALSE, don't need to save the profile to NV flash.\r
1024 \r
1025   @retval EFI_SUCCESS      Add user info to user profile successfully.\r
1026   @retval Others           Fail to add user info to user profile.\r
1027 \r
1028 **/\r
1029 EFI_STATUS\r
1030 AddUserInfo (\r
1031   IN  USER_PROFILE_ENTRY                        *User,\r
1032   IN  UINT8                                     *Info,\r
1033   IN  UINTN                                     InfoSize,\r
1034   OUT EFI_USER_INFO                             **UserInfo, OPTIONAL\r
1035   IN  BOOLEAN                                   Save\r
1036   )\r
1037 {\r
1038   EFI_STATUS  Status;\r
1039 \r
1040   if ((Info == NULL) || (User == NULL)) {\r
1041     return EFI_INVALID_PARAMETER;\r
1042   }\r
1043 \r
1044   //\r
1045   // Check user profile handle.\r
1046   //\r
1047   Status = FindUserProfile (&User, FALSE, NULL);\r
1048   if (EFI_ERROR (Status)) {\r
1049     return Status;\r
1050   }\r
1051 \r
1052   //\r
1053   // Check user information memory size.\r
1054   //\r
1055   if (User->MaxProfileSize - User->UserProfileSize < ALIGN_VARIABLE (InfoSize)) {\r
1056     if (!ExpandUserProfile (User, ALIGN_VARIABLE (InfoSize))) {\r
1057       return EFI_OUT_OF_RESOURCES;\r
1058     }\r
1059   }\r
1060 \r
1061   //\r
1062   // Add new user information.\r
1063   //\r
1064   CopyMem (User->ProfileInfo + User->UserProfileSize, Info, InfoSize);\r
1065   if (UserInfo != NULL) {\r
1066     *UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + User->UserProfileSize);\r
1067   }\r
1068   User->UserProfileSize += ALIGN_VARIABLE (InfoSize);\r
1069 \r
1070   //\r
1071   // Save user profile information.\r
1072   //\r
1073   if (Save) {\r
1074     Status = SaveNvUserProfile (User, FALSE);\r
1075   }\r
1076 \r
1077   return Status;\r
1078 }\r
1079 \r
1080 \r
1081 /**\r
1082   Get the user info from the specified user info handle.\r
1083 \r
1084   @param[in]      User            Point to the user profile.\r
1085   @param[in]      UserInfo        Point to the user information record to get.\r
1086   @param[out]     Info            On entry, points to a buffer of at least *InfoSize bytes.\r
1087                                   On exit, holds the user information.\r
1088   @param[in, out] InfoSize        On entry, points to the size of Info.\r
1089                                   On return, points to the size of the user information.\r
1090   @param[in]      ChkRight        If TRUE, check the user info attribute.\r
1091                                   If FALSE, don't check the user info attribute.\r
1092 \r
1093 \r
1094   @retval EFI_ACCESS_DENIED       The information cannot be accessed by the current user.\r
1095   @retval EFI_INVALID_PARAMETER   InfoSize is NULL or UserInfo is NULL.\r
1096   @retval EFI_BUFFER_TOO_SMALL    The number of bytes specified by *InfoSize is too small to hold the\r
1097                                   returned data. The actual size required is returned in *InfoSize.\r
1098   @retval EFI_SUCCESS             Information returned successfully.\r
1099 \r
1100 **/\r
1101 EFI_STATUS\r
1102 GetUserInfo (\r
1103   IN        USER_PROFILE_ENTRY                  *User,\r
1104   IN        EFI_USER_INFO                       *UserInfo,\r
1105   OUT       EFI_USER_INFO                       *Info,\r
1106   IN OUT    UINTN                               *InfoSize,\r
1107   IN        BOOLEAN                             ChkRight\r
1108   )\r
1109 {\r
1110   EFI_STATUS  Status;\r
1111 \r
1112   if ((InfoSize == NULL) || (UserInfo == NULL)) {\r
1113     return EFI_INVALID_PARAMETER;\r
1114   }\r
1115 \r
1116   if ((*InfoSize != 0) && (Info == NULL)) {\r
1117     return EFI_INVALID_PARAMETER;\r
1118   }\r
1119 \r
1120   //\r
1121   // Find the user information to get.\r
1122   //\r
1123   Status = FindUserInfo (User, &UserInfo, FALSE, NULL);\r
1124   if (EFI_ERROR (Status)) {\r
1125     return Status;\r
1126   }\r
1127 \r
1128   //\r
1129   // Check information attributes.\r
1130   //\r
1131   if (ChkRight) {\r
1132     switch (UserInfo->InfoAttribs & EFI_USER_INFO_ACCESS) {\r
1133     case EFI_USER_INFO_PRIVATE:\r
1134     case EFI_USER_INFO_PROTECTED:\r
1135       if (User != mCurrentUser) {\r
1136         return EFI_ACCESS_DENIED;\r
1137       }\r
1138       break;\r
1139 \r
1140     case EFI_USER_INFO_PUBLIC:\r
1141       break;\r
1142 \r
1143     default:\r
1144       return EFI_INVALID_PARAMETER;\r
1145       break;\r
1146     }\r
1147   }\r
1148 \r
1149   //\r
1150   // Get user information.\r
1151   //\r
1152   if (UserInfo->InfoSize > *InfoSize) {\r
1153     *InfoSize = UserInfo->InfoSize;\r
1154     return EFI_BUFFER_TOO_SMALL;\r
1155   }\r
1156 \r
1157   *InfoSize = UserInfo->InfoSize;\r
1158   if (Info != NULL) {\r
1159     CopyMem (Info, UserInfo, *InfoSize);\r
1160   }\r
1161 \r
1162   return EFI_SUCCESS;\r
1163 }\r
1164 \r
1165 \r
1166 /**\r
1167   Delete the specified user information from user profile.\r
1168 \r
1169   @param[in]  User        Point to the user profile.\r
1170   @param[in]  Info        Point to the user information record to delete.\r
1171   @param[in]  Save        If TRUE, save the profile to NV flash.\r
1172                           If FALSE, don't need to save the profile to NV flash.\r
1173 \r
1174   @retval EFI_SUCCESS     Delete user info from user profile successfully.\r
1175   @retval Others          Fail to delete user info from user profile.\r
1176 \r
1177 **/\r
1178 EFI_STATUS\r
1179 DelUserInfo (\r
1180   IN  USER_PROFILE_ENTRY                        *User,\r
1181   IN  EFI_USER_INFO                             *Info,\r
1182   IN  BOOLEAN                                   Save\r
1183   )\r
1184 {\r
1185   EFI_STATUS  Status;\r
1186   UINTN       Offset;\r
1187   UINTN       NextOffset;\r
1188 \r
1189   //\r
1190   // Check user information handle.\r
1191   //\r
1192   Status = FindUserInfo (User, &Info, FALSE, &Offset);\r
1193   if (EFI_ERROR (Status)) {\r
1194     return Status;\r
1195   }\r
1196 \r
1197   if (Info->InfoType == EFI_USER_INFO_IDENTIFIER_RECORD) {\r
1198     return EFI_ACCESS_DENIED;\r
1199   }\r
1200 \r
1201   //\r
1202   // Delete the specified user information.\r
1203   //\r
1204   NextOffset = Offset + ALIGN_VARIABLE (Info->InfoSize);\r
1205   User->UserProfileSize -= ALIGN_VARIABLE (Info->InfoSize);\r
1206   if (Offset < User->UserProfileSize) {\r
1207     CopyMem (User->ProfileInfo + Offset, User->ProfileInfo + NextOffset, User->UserProfileSize - Offset);\r
1208   }\r
1209 \r
1210   if (Save) {\r
1211     Status = SaveNvUserProfile (User, FALSE);\r
1212   }\r
1213 \r
1214   return Status;\r
1215 }\r
1216 \r
1217 \r
1218 /**\r
1219   Add or update user information.\r
1220 \r
1221   @param[in]      User           Point to the user profile.\r
1222   @param[in, out] UserInfo       On entry, points to the user information to modify,\r
1223                                  or NULL to add a new UserInfo.\r
1224                                  On return, points to the modified user information.\r
1225   @param[in]      Info           Points to the new user information.\r
1226   @param[in]      InfoSize       The size of Info,in bytes.\r
1227 \r
1228   @retval EFI_INVALID_PARAMETER  UserInfo is NULL or Info is NULL.\r
1229   @retval EFI_ACCESS_DENIED      The record is exclusive.\r
1230   @retval EFI_SUCCESS            User information was successfully changed/added.\r
1231 \r
1232 **/\r
1233 EFI_STATUS\r
1234 ModifyUserInfo (\r
1235   IN        USER_PROFILE_ENTRY                  *User,\r
1236   IN OUT    EFI_USER_INFO                       **UserInfo,\r
1237   IN CONST  EFI_USER_INFO                       *Info,\r
1238   IN        UINTN                               InfoSize\r
1239   )\r
1240 {\r
1241   EFI_STATUS    Status;\r
1242   UINTN         PayloadLen;\r
1243   EFI_USER_INFO *OldInfo;\r
1244 \r
1245   if ((UserInfo == NULL) || (Info == NULL)) {\r
1246     return EFI_INVALID_PARAMETER;\r
1247   }\r
1248 \r
1249   if (InfoSize < sizeof (EFI_USER_INFO) || InfoSize != Info->InfoSize) {\r
1250     return EFI_INVALID_PARAMETER;\r
1251   }\r
1252 \r
1253   //\r
1254   // Check user information.\r
1255   //\r
1256   if (Info->InfoType == EFI_USER_INFO_IDENTIFIER_RECORD) {\r
1257     return EFI_ACCESS_DENIED;\r
1258   }\r
1259 \r
1260   if (!CheckUserInfo (Info)) {\r
1261     return EFI_INVALID_PARAMETER;\r
1262   }\r
1263 \r
1264 \r
1265   if (*UserInfo == NULL) {\r
1266     //\r
1267     // Add new user information.\r
1268     //\r
1269     OldInfo = NULL;\r
1270     do {\r
1271       Status = FindUserInfoByType (User, &OldInfo, Info->InfoType);\r
1272       if (EFI_ERROR (Status)) {\r
1273         break;\r
1274       }\r
1275       ASSERT (OldInfo != NULL);\r
1276 \r
1277       if (((OldInfo->InfoAttribs & EFI_USER_INFO_EXCLUSIVE) != 0) ||\r
1278            ((Info->InfoAttribs & EFI_USER_INFO_EXCLUSIVE) != 0)) {\r
1279         //\r
1280         //  Same type can not co-exist for exclusive information.\r
1281         //\r
1282         return EFI_ACCESS_DENIED;\r
1283       }\r
1284 \r
1285       //\r
1286       // Check whether it exists in DB.\r
1287       //\r
1288       if (Info->InfoSize != OldInfo->InfoSize) {\r
1289         continue;\r
1290       }\r
1291 \r
1292       if (!CompareGuid (&OldInfo->Credential, &Info->Credential)) {\r
1293         continue;\r
1294       }\r
1295 \r
1296       PayloadLen = Info->InfoSize - sizeof (EFI_USER_INFO);\r
1297       if (PayloadLen == 0) {\r
1298         continue;\r
1299       }\r
1300 \r
1301       if (CompareMem ((UINT8 *)(OldInfo + 1), (UINT8 *)(Info + 1), PayloadLen) != 0) {\r
1302         continue;\r
1303       }\r
1304 \r
1305       //\r
1306       // Yes. The new info is as same as the one in profile.\r
1307       //\r
1308       return EFI_SUCCESS;\r
1309     } while (!EFI_ERROR (Status));\r
1310 \r
1311     Status = AddUserInfo (User, (UINT8 *) Info, InfoSize, UserInfo, TRUE);\r
1312     return Status;\r
1313   }\r
1314 \r
1315   //\r
1316   // Modify existing user information.\r
1317   //\r
1318   OldInfo = *UserInfo;\r
1319   if (OldInfo->InfoType != Info->InfoType) {\r
1320     return EFI_INVALID_PARAMETER;\r
1321   }\r
1322 \r
1323   if (((Info->InfoAttribs & EFI_USER_INFO_EXCLUSIVE) != 0) &&\r
1324        (OldInfo->InfoAttribs & EFI_USER_INFO_EXCLUSIVE) == 0) {\r
1325     //\r
1326     // Try to add exclusive attrib in new info.\r
1327     // Check whether there is another information with the same type in profile.\r
1328     //\r
1329     OldInfo = NULL;\r
1330     do {\r
1331       Status = FindUserInfoByType (User, &OldInfo, Info->InfoType);\r
1332       if (EFI_ERROR (Status)) {\r
1333         break;\r
1334       }\r
1335       if (OldInfo != *UserInfo) {\r
1336         //\r
1337         // There is another information with the same type in profile.\r
1338         // Therefore, can't modify existing user information to add exclusive attribute.\r
1339         //\r
1340         return EFI_ACCESS_DENIED;\r
1341       }\r
1342     } while (TRUE);\r
1343   }\r
1344 \r
1345   Status = DelUserInfo (User, *UserInfo, FALSE);\r
1346   if (EFI_ERROR (Status)) {\r
1347     return Status;\r
1348   }\r
1349 \r
1350   return AddUserInfo (User, (UINT8 *) Info, InfoSize, UserInfo, TRUE);\r
1351 }\r
1352 \r
1353 \r
1354 /**\r
1355   Delete the user profile from non-volatile memory and database.\r
1356 \r
1357   @param[in]  User              Points to the user profile.\r
1358 \r
1359   @retval EFI_SUCCESS      Delete user from the user profile successfully.\r
1360   @retval Others           Fail to delete user from user profile\r
1361 \r
1362 **/\r
1363 EFI_STATUS\r
1364 DelUserProfile (\r
1365   IN  USER_PROFILE_ENTRY                        *User\r
1366   )\r
1367 {\r
1368   EFI_STATUS          Status;\r
1369   UINTN               Index;\r
1370 \r
1371   //\r
1372   // Check whether it is in the user profile database.\r
1373   //\r
1374   Status = FindUserProfile (&User, FALSE, &Index);\r
1375   if (EFI_ERROR (Status)) {\r
1376     return EFI_INVALID_PARAMETER;\r
1377   }\r
1378 \r
1379   //\r
1380   // Check whether it is the current user.\r
1381   //\r
1382   if (User == mCurrentUser) {\r
1383     return EFI_ACCESS_DENIED;\r
1384   }\r
1385 \r
1386   //\r
1387   // Delete user profile from the non-volatile memory.\r
1388   //\r
1389   Status    = SaveNvUserProfile (mUserProfileDb->UserProfile[mUserProfileDb->UserProfileNum - 1], TRUE);\r
1390   if (EFI_ERROR (Status)) {\r
1391     return Status;\r
1392   }\r
1393   mUserProfileDb->UserProfileNum--;\r
1394 \r
1395   //\r
1396   // Modify user profile database.\r
1397   //\r
1398   if (Index != mUserProfileDb->UserProfileNum) {\r
1399     mUserProfileDb->UserProfile[Index] = mUserProfileDb->UserProfile[mUserProfileDb->UserProfileNum];\r
1400     CopyMem (\r
1401       ((USER_PROFILE_ENTRY *) mUserProfileDb->UserProfile[Index])->UserVarName,\r
1402       User->UserVarName,\r
1403       sizeof (User->UserVarName)\r
1404       );\r
1405     Status = SaveNvUserProfile (mUserProfileDb->UserProfile[Index], FALSE);\r
1406     if (EFI_ERROR (Status)) {\r
1407       return Status;\r
1408     }\r
1409   }\r
1410   //\r
1411   // Delete user profile information.\r
1412   //\r
1413   if (User->ProfileInfo != NULL) {\r
1414     FreePool (User->ProfileInfo);\r
1415   }\r
1416 \r
1417   FreePool (User);\r
1418   return EFI_SUCCESS;\r
1419 }\r
1420 \r
1421 \r
1422 /**\r
1423   Add user profile to user profile database.\r
1424 \r
1425   @param[out]   UserProfile   Point to the newly added user profile.\r
1426   @param[in]    ProfileSize   The size of the user profile.\r
1427   @param[in]    ProfileInfo   Point to the user profie data.\r
1428   @param[in]    Save          If TRUE, save the new added profile to NV flash.\r
1429                               If FALSE, don't save the profile to NV flash.\r
1430 \r
1431   @retval EFI_SUCCESS         Add user profile to user profile database successfully.\r
1432   @retval Others              Fail to add user profile to user profile database.\r
1433 \r
1434 **/\r
1435 EFI_STATUS\r
1436 AddUserProfile (\r
1437      OUT  USER_PROFILE_ENTRY                    **UserProfile, OPTIONAL\r
1438   IN      UINTN                                 ProfileSize,\r
1439   IN      UINT8                                 *ProfileInfo,\r
1440   IN      BOOLEAN                               Save\r
1441   )\r
1442 {\r
1443   EFI_STATUS              Status;\r
1444   USER_PROFILE_ENTRY      *User;\r
1445 \r
1446   //\r
1447   // Check the data format to be added.\r
1448   //\r
1449   if (!CheckProfileInfo (ProfileInfo, ProfileSize)) {\r
1450     return EFI_SECURITY_VIOLATION;\r
1451   }\r
1452 \r
1453   //\r
1454   // Create user profile entry.\r
1455   //\r
1456   User = AllocateZeroPool (sizeof (USER_PROFILE_ENTRY));\r
1457   if (User == NULL) {\r
1458     return EFI_OUT_OF_RESOURCES;\r
1459   }\r
1460   //\r
1461   // Add the entry to the user profile database.\r
1462   //\r
1463   if (mUserProfileDb->UserProfileNum == mUserProfileDb->MaxProfileNum) {\r
1464     if (!ExpandUsermUserProfileDb ()) {\r
1465       FreePool (User);\r
1466       return EFI_OUT_OF_RESOURCES;\r
1467     }\r
1468   }\r
1469 \r
1470   UnicodeSPrint (\r
1471     User->UserVarName,\r
1472     sizeof (User->UserVarName),\r
1473     L"User%04x",\r
1474     mUserProfileDb->UserProfileNum\r
1475     );\r
1476   User->UserProfileSize = 0;\r
1477   User->MaxProfileSize  = 0;\r
1478   User->ProfileInfo     = NULL;\r
1479   mUserProfileDb->UserProfile[mUserProfileDb->UserProfileNum] = (EFI_USER_PROFILE_HANDLE) User;\r
1480   mUserProfileDb->UserProfileNum++;\r
1481 \r
1482   //\r
1483   // Add user profile information.\r
1484   //\r
1485   Status = AddUserInfo (User, ProfileInfo, ProfileSize, NULL, Save);\r
1486   if (EFI_ERROR (Status)) {\r
1487     DelUserProfile (User);\r
1488     return Status;\r
1489   }\r
1490   //\r
1491   // Set new user profile handle.\r
1492   //\r
1493   if (UserProfile != NULL) {\r
1494     *UserProfile = User;\r
1495   }\r
1496 \r
1497   return EFI_SUCCESS;\r
1498 }\r
1499 \r
1500 \r
1501 /**\r
1502   This function creates a new user profile with only a new user identifier\r
1503   attached and returns its handle. The user profile is non-volatile, but the\r
1504   handle User can change across reboots.\r
1505 \r
1506   @param[out]  User               Handle of a new user profile.\r
1507 \r
1508   @retval EFI_SUCCESS             User profile was successfully created.\r
1509   @retval Others                  Fail to create user profile\r
1510 \r
1511 **/\r
1512 EFI_STATUS\r
1513 CreateUserProfile (\r
1514   OUT USER_PROFILE_ENTRY                        **User\r
1515   )\r
1516 {\r
1517   EFI_STATUS    Status;\r
1518   EFI_USER_INFO *UserInfo;\r
1519 \r
1520   if (User == NULL) {\r
1521     return EFI_INVALID_PARAMETER;\r
1522   }\r
1523   //\r
1524   // Generate user id information.\r
1525   //\r
1526   UserInfo = AllocateZeroPool (sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_IDENTIFIER));\r
1527   if (UserInfo == NULL) {\r
1528     return EFI_OUT_OF_RESOURCES;\r
1529   }\r
1530 \r
1531   UserInfo->InfoType    = EFI_USER_INFO_IDENTIFIER_RECORD;\r
1532   UserInfo->InfoSize    = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_IDENTIFIER);\r
1533   UserInfo->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;\r
1534   GenerateUserId ((UINT8 *) (UserInfo + 1));\r
1535 \r
1536   //\r
1537   // Add user profile to the user profile database.\r
1538   //\r
1539   Status = AddUserProfile (User, UserInfo->InfoSize, (UINT8 *) UserInfo, TRUE);\r
1540   FreePool (UserInfo);\r
1541   return Status;\r
1542 }\r
1543 \r
1544 \r
1545 /**\r
1546   Add a default user profile to user profile database.\r
1547 \r
1548   @retval EFI_SUCCESS             A default user profile is added successfully.\r
1549   @retval Others                  Fail to add a default user profile\r
1550 \r
1551 **/\r
1552 EFI_STATUS\r
1553 AddDefaultUserProfile (\r
1554   VOID\r
1555   )\r
1556 {\r
1557   EFI_STATUS                    Status;\r
1558   USER_PROFILE_ENTRY            *User;\r
1559   EFI_USER_INFO                 *Info;\r
1560   EFI_USER_INFO                 *NewInfo;\r
1561   EFI_USER_INFO_CREATE_DATE     CreateDate;\r
1562   EFI_USER_INFO_USAGE_COUNT     UsageCount;\r
1563   EFI_USER_INFO_ACCESS_CONTROL  *Access;\r
1564   EFI_USER_INFO_IDENTITY_POLICY *Policy;\r
1565 \r
1566   //\r
1567   // Create a user profile.\r
1568   //\r
1569   Status = CreateUserProfile (&User);\r
1570   if (EFI_ERROR (Status)) {\r
1571     return Status;\r
1572   }\r
1573 \r
1574   //\r
1575   // Allocate a buffer to add all default user information.\r
1576   //\r
1577   Info = AllocateZeroPool (sizeof (EFI_USER_INFO) + INFO_PAYLOAD_SIZE);\r
1578   if (Info == NULL) {\r
1579     return EFI_OUT_OF_RESOURCES;\r
1580   }\r
1581 \r
1582   //\r
1583   // Add user name.\r
1584   //\r
1585   Info->InfoType    = EFI_USER_INFO_NAME_RECORD;\r
1586   Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;\r
1587   Info->InfoSize    = sizeof (EFI_USER_INFO) + sizeof (mUserName);\r
1588   CopyMem ((UINT8 *) (Info + 1), mUserName, sizeof (mUserName));\r
1589   NewInfo = NULL;\r
1590   Status  = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);\r
1591   if (EFI_ERROR (Status)) {\r
1592     goto Done;\r
1593   }\r
1594 \r
1595   //\r
1596   // Add user profile create date record.\r
1597   //\r
1598   Info->InfoType    = EFI_USER_INFO_CREATE_DATE_RECORD;\r
1599   Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;\r
1600   Info->InfoSize    = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_CREATE_DATE);\r
1601   Status            = gRT->GetTime (&CreateDate, NULL);\r
1602   if (EFI_ERROR (Status)) {\r
1603     goto Done;\r
1604   }\r
1605 \r
1606   CopyMem ((UINT8 *) (Info + 1), &CreateDate, sizeof (EFI_USER_INFO_CREATE_DATE));\r
1607   NewInfo = NULL;\r
1608   Status  = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);\r
1609   if (EFI_ERROR (Status)) {\r
1610     goto Done;\r
1611   }\r
1612 \r
1613   //\r
1614   // Add user profile usage count record.\r
1615   //\r
1616   Info->InfoType    = EFI_USER_INFO_USAGE_COUNT_RECORD;\r
1617   Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;\r
1618   Info->InfoSize    = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_USAGE_COUNT);\r
1619   UsageCount        = 0;\r
1620   CopyMem ((UINT8 *) (Info + 1), &UsageCount, sizeof (EFI_USER_INFO_USAGE_COUNT));\r
1621   NewInfo = NULL;\r
1622   Status  = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);\r
1623   if (EFI_ERROR (Status)) {\r
1624     goto Done;\r
1625   }\r
1626 \r
1627   //\r
1628   // Add user access right.\r
1629   //\r
1630   Info->InfoType    = EFI_USER_INFO_ACCESS_POLICY_RECORD;\r
1631   Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;\r
1632   Access            = (EFI_USER_INFO_ACCESS_CONTROL *) (Info + 1);\r
1633   Access->Type      = EFI_USER_INFO_ACCESS_MANAGE;\r
1634   Access->Size      = sizeof (EFI_USER_INFO_ACCESS_CONTROL);\r
1635   Info->InfoSize    = sizeof (EFI_USER_INFO) + Access->Size;\r
1636   NewInfo = NULL;\r
1637   Status  = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);\r
1638   if (EFI_ERROR (Status)) {\r
1639     goto Done;\r
1640   }\r
1641 \r
1642   //\r
1643   // Add user identity policy.\r
1644   //\r
1645   Info->InfoType    = EFI_USER_INFO_IDENTITY_POLICY_RECORD;\r
1646   Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PRIVATE | EFI_USER_INFO_EXCLUSIVE;\r
1647   Policy            = (EFI_USER_INFO_IDENTITY_POLICY *) (Info + 1);\r
1648   Policy->Type      = EFI_USER_INFO_IDENTITY_TRUE;\r
1649   Policy->Length    = sizeof (EFI_USER_INFO_IDENTITY_POLICY);\r
1650   Info->InfoSize    = sizeof (EFI_USER_INFO) + Policy->Length;\r
1651   NewInfo = NULL;\r
1652   Status  = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);\r
1653 \r
1654 Done:\r
1655   FreePool (Info);\r
1656   return Status;\r
1657 }\r
1658 \r
1659 \r
1660 /**\r
1661   Publish current user information into EFI System Configuration Table.\r
1662 \r
1663   By UEFI spec, the User Identity Manager will publish the current user profile\r
1664   into the EFI System Configuration Table. Currently, only the user identifier and user\r
1665   name are published.\r
1666 \r
1667   @retval EFI_SUCCESS      Current user information is published successfully.\r
1668   @retval Others           Fail to publish current user information\r
1669 \r
1670 **/\r
1671 EFI_STATUS\r
1672 PublishUserTable (\r
1673   VOID\r
1674   )\r
1675 {\r
1676   EFI_STATUS              Status;\r
1677   EFI_CONFIGURATION_TABLE *EfiConfigurationTable;\r
1678   EFI_USER_INFO_TABLE     *UserInfoTable;\r
1679   EFI_USER_INFO           *IdInfo;\r
1680   EFI_USER_INFO           *NameInfo;\r
1681 \r
1682   Status = EfiGetSystemConfigurationTable (\r
1683              &gEfiUserManagerProtocolGuid,\r
1684              (VOID **) &EfiConfigurationTable\r
1685              );\r
1686   if (!EFI_ERROR (Status)) {\r
1687     //\r
1688     // The table existed!\r
1689     //\r
1690     return EFI_SUCCESS;\r
1691   }\r
1692 \r
1693   //\r
1694   // Get user ID information.\r
1695   //\r
1696   IdInfo  = NULL;\r
1697   Status  = FindUserInfoByType (mCurrentUser, &IdInfo, EFI_USER_INFO_IDENTIFIER_RECORD);\r
1698   if (EFI_ERROR (Status)) {\r
1699     return Status;\r
1700 \r
1701   }\r
1702   //\r
1703   // Get user name information.\r
1704   //\r
1705   NameInfo  = NULL;\r
1706   Status    = FindUserInfoByType (mCurrentUser, &NameInfo, EFI_USER_INFO_NAME_RECORD);\r
1707   if (EFI_ERROR (Status)) {\r
1708     return Status;\r
1709   }\r
1710 \r
1711   //\r
1712   // Allocate a buffer for user information table.\r
1713   //\r
1714   UserInfoTable = (EFI_USER_INFO_TABLE *) AllocateRuntimePool (\r
1715                                             sizeof (EFI_USER_INFO_TABLE) +\r
1716                                             IdInfo->InfoSize +\r
1717                                             NameInfo->InfoSize\r
1718                                             );\r
1719   if (UserInfoTable == NULL) {\r
1720     Status = EFI_OUT_OF_RESOURCES;\r
1721     return Status;\r
1722   }\r
1723 \r
1724   UserInfoTable->Size = sizeof (EFI_USER_INFO_TABLE);\r
1725 \r
1726   //\r
1727   // Append the user information to the user info table\r
1728   //\r
1729   CopyMem ((UINT8 *) UserInfoTable + UserInfoTable->Size, (UINT8 *) IdInfo, IdInfo->InfoSize);\r
1730   UserInfoTable->Size += IdInfo->InfoSize;\r
1731 \r
1732   CopyMem ((UINT8 *) UserInfoTable + UserInfoTable->Size, (UINT8 *) NameInfo, NameInfo->InfoSize);\r
1733   UserInfoTable->Size += NameInfo->InfoSize;\r
1734 \r
1735   Status = gBS->InstallConfigurationTable (&gEfiUserManagerProtocolGuid, (VOID *) UserInfoTable);\r
1736   return Status;\r
1737 }\r
1738 \r
1739 \r
1740 /**\r
1741   Get the user's identity type.\r
1742 \r
1743   The identify manager only supports the identity policy in which the credential\r
1744   provider handles are connected by the operator 'AND' or 'OR'.\r
1745 \r
1746 \r
1747   @param[in]   User              Handle of a user profile.\r
1748   @param[out]  PolicyType        Point to the identity type.\r
1749 \r
1750   @retval EFI_SUCCESS            Get user's identity type successfully.\r
1751   @retval Others                 Fail to get user's identity type.\r
1752 \r
1753 **/\r
1754 EFI_STATUS\r
1755 GetIdentifyType (\r
1756   IN      EFI_USER_PROFILE_HANDLE               User,\r
1757      OUT  UINT8                                 *PolicyType\r
1758   )\r
1759 {\r
1760   EFI_STATUS                    Status;\r
1761   EFI_USER_INFO                 *IdentifyInfo;\r
1762   UINTN                         TotalLen;\r
1763   EFI_USER_INFO_IDENTITY_POLICY *Identity;\r
1764 \r
1765   //\r
1766   // Get user identify policy information.\r
1767   //\r
1768   IdentifyInfo  = NULL;\r
1769   Status        = FindUserInfoByType (User, &IdentifyInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);\r
1770   if (EFI_ERROR (Status)) {\r
1771     return Status;\r
1772   }\r
1773   ASSERT (IdentifyInfo != NULL);\r
1774 \r
1775   //\r
1776   // Search the user identify policy according to type.\r
1777   //\r
1778   TotalLen    = 0;\r
1779   *PolicyType = EFI_USER_INFO_IDENTITY_FALSE;\r
1780   while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) {\r
1781     Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen);\r
1782     if (Identity->Type == EFI_USER_INFO_IDENTITY_AND) {\r
1783       *PolicyType = EFI_USER_INFO_IDENTITY_AND;\r
1784       break;\r
1785     }\r
1786 \r
1787     if (Identity->Type == EFI_USER_INFO_IDENTITY_OR) {\r
1788       *PolicyType = EFI_USER_INFO_IDENTITY_OR;\r
1789       break;\r
1790     }\r
1791     TotalLen += Identity->Length;\r
1792   }\r
1793   return EFI_SUCCESS;\r
1794 }\r
1795 \r
1796 \r
1797 /**\r
1798   Identify the User by the specfied provider.\r
1799 \r
1800   @param[in]  User                Handle of a user profile.\r
1801   @param[in]  Provider            Points to the identifier of credential provider.\r
1802 \r
1803   @retval EFI_INVALID_PARAMETER   Provider is NULL.\r
1804   @retval EFI_NOT_FOUND           Fail to identify the specified user.\r
1805   @retval EFI_SUCCESS             User is identified successfully.\r
1806 \r
1807 **/\r
1808 EFI_STATUS\r
1809 IdentifyByProviderId (\r
1810   IN  EFI_USER_PROFILE_HANDLE                   User,\r
1811   IN  EFI_GUID                                  *Provider\r
1812   )\r
1813 {\r
1814   EFI_STATUS                    Status;\r
1815   EFI_USER_INFO_IDENTIFIER      UserId;\r
1816   UINTN                         Index;\r
1817   EFI_CREDENTIAL_LOGON_FLAGS    AutoLogon;\r
1818   EFI_HII_HANDLE                HiiHandle;\r
1819   EFI_GUID                      FormSetId;\r
1820   EFI_FORM_ID                   FormId;\r
1821   EFI_USER_CREDENTIAL2_PROTOCOL *UserCredential;\r
1822 \r
1823   if (Provider == NULL) {\r
1824     return EFI_INVALID_PARAMETER;\r
1825   }\r
1826 \r
1827   //\r
1828   // Check the user ID identified by the specified credential provider.\r
1829   //\r
1830   for (Index = 0; Index < mProviderDb->Count; Index++) {\r
1831     //\r
1832     // Check credential provider class.\r
1833     //\r
1834     UserCredential = mProviderDb->Provider[Index];\r
1835     if (CompareGuid (&UserCredential->Identifier, Provider)) {\r
1836       Status = UserCredential->Select (UserCredential, &AutoLogon);\r
1837       if (EFI_ERROR (Status)) {\r
1838         return Status;\r
1839       }\r
1840 \r
1841       if ((AutoLogon & EFI_CREDENTIAL_LOGON_FLAG_AUTO) == 0) {\r
1842         //\r
1843         // Get credential provider form.\r
1844         //\r
1845         Status = UserCredential->Form (\r
1846                                    UserCredential,\r
1847                                    &HiiHandle,\r
1848                                    &FormSetId,\r
1849                                    &FormId\r
1850                                    );\r
1851         if (!EFI_ERROR (Status)) {\r
1852           //\r
1853           // Send form to get user input.\r
1854           //\r
1855           Status = mCallbackInfo->FormBrowser2->SendForm (\r
1856                                                   mCallbackInfo->FormBrowser2,\r
1857                                                   &HiiHandle,\r
1858                                                   1,\r
1859                                                   &FormSetId,\r
1860                                                   FormId,\r
1861                                                   NULL,\r
1862                                                   NULL\r
1863                                                   );\r
1864           if (EFI_ERROR (Status)) {\r
1865             return Status;\r
1866           }\r
1867         }\r
1868       }\r
1869 \r
1870       Status = UserCredential->User (UserCredential, User, &UserId);\r
1871       if (EFI_ERROR (Status)) {\r
1872         return Status;\r
1873       }\r
1874 \r
1875       Status = UserCredential->Deselect (UserCredential);\r
1876       if (EFI_ERROR (Status)) {\r
1877         return Status;\r
1878       }\r
1879 \r
1880       return EFI_SUCCESS;\r
1881     }\r
1882   }\r
1883 \r
1884   return EFI_NOT_FOUND;\r
1885 }\r
1886 \r
1887 \r
1888 /**\r
1889   Update user information when user is logon on successfully.\r
1890 \r
1891   @param[in]  User         Points to user profile.\r
1892 \r
1893   @retval EFI_SUCCESS      Update user information successfully.\r
1894   @retval Others           Fail to update user information.\r
1895 \r
1896 **/\r
1897 EFI_STATUS\r
1898 UpdateUserInfo (\r
1899   IN  USER_PROFILE_ENTRY                        *User\r
1900   )\r
1901 {\r
1902   EFI_STATUS                Status;\r
1903   EFI_USER_INFO             *Info;\r
1904   EFI_USER_INFO             *NewInfo;\r
1905   EFI_USER_INFO_CREATE_DATE Date;\r
1906   EFI_USER_INFO_USAGE_COUNT UsageCount;\r
1907   UINTN                     InfoLen;\r
1908 \r
1909   //\r
1910   // Allocate a buffer to update user's date record and usage record.\r
1911   //\r
1912   InfoLen  = MAX (sizeof (EFI_USER_INFO_CREATE_DATE), sizeof (EFI_USER_INFO_USAGE_COUNT));\r
1913   Info     = AllocateZeroPool (sizeof (EFI_USER_INFO) + InfoLen);\r
1914   if (Info == NULL) {\r
1915     return EFI_OUT_OF_RESOURCES;\r
1916   }\r
1917 \r
1918   //\r
1919   // Check create date record.\r
1920   //\r
1921   NewInfo = NULL;\r
1922   Status  = FindUserInfoByType (User, &NewInfo, EFI_USER_INFO_CREATE_DATE_RECORD);\r
1923   if (Status == EFI_NOT_FOUND) {\r
1924     Info->InfoType    = EFI_USER_INFO_CREATE_DATE_RECORD;\r
1925     Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;\r
1926     Info->InfoSize    = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_CREATE_DATE);\r
1927     Status            = gRT->GetTime (&Date, NULL);\r
1928     if (EFI_ERROR (Status)) {\r
1929       FreePool (Info);\r
1930       return Status;\r
1931     }\r
1932 \r
1933     CopyMem ((UINT8 *) (Info + 1), &Date, sizeof (EFI_USER_INFO_CREATE_DATE));\r
1934     NewInfo = NULL;\r
1935     Status  = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);\r
1936     if (EFI_ERROR (Status)) {\r
1937       FreePool (Info);\r
1938       return Status;\r
1939     }\r
1940   }\r
1941 \r
1942   //\r
1943   // Update usage date record.\r
1944   //\r
1945   NewInfo = NULL;\r
1946   Status  = FindUserInfoByType (User, &NewInfo, EFI_USER_INFO_USAGE_DATE_RECORD);\r
1947   if ((Status == EFI_SUCCESS) || (Status == EFI_NOT_FOUND)) {\r
1948     Info->InfoType    = EFI_USER_INFO_USAGE_DATE_RECORD;\r
1949     Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;\r
1950     Info->InfoSize    = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_USAGE_DATE);\r
1951     Status            = gRT->GetTime (&Date, NULL);\r
1952     if (EFI_ERROR (Status)) {\r
1953       FreePool (Info);\r
1954       return Status;\r
1955     }\r
1956 \r
1957     CopyMem ((UINT8 *) (Info + 1), &Date, sizeof (EFI_USER_INFO_USAGE_DATE));\r
1958     Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);\r
1959     if (EFI_ERROR (Status)) {\r
1960       FreePool (Info);\r
1961       return Status;\r
1962     }\r
1963   }\r
1964 \r
1965   //\r
1966   // Update usage count record.\r
1967   //\r
1968   UsageCount  = 0;\r
1969   NewInfo     = NULL;\r
1970   Status      = FindUserInfoByType (User, &NewInfo, EFI_USER_INFO_USAGE_COUNT_RECORD);\r
1971   //\r
1972   // Get usage count.\r
1973   //\r
1974   if (Status == EFI_SUCCESS) {\r
1975     CopyMem (&UsageCount, (UINT8 *) (NewInfo + 1), sizeof (EFI_USER_INFO_USAGE_COUNT));\r
1976   }\r
1977 \r
1978   UsageCount++;\r
1979   if ((Status == EFI_SUCCESS) || (Status == EFI_NOT_FOUND)) {\r
1980     Info->InfoType    = EFI_USER_INFO_USAGE_COUNT_RECORD;\r
1981     Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;\r
1982     Info->InfoSize    = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_USAGE_COUNT);\r
1983     CopyMem ((UINT8 *) (Info + 1), &UsageCount, sizeof (EFI_USER_INFO_USAGE_COUNT));\r
1984     Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);\r
1985     if (EFI_ERROR (Status)) {\r
1986       FreePool (Info);\r
1987       return Status;\r
1988     }\r
1989   }\r
1990 \r
1991   FreePool (Info);\r
1992   return EFI_SUCCESS;\r
1993 }\r
1994 \r
1995 \r
1996 /**\r
1997   Add a credenetial provider item in form.\r
1998 \r
1999   @param[in]  ProviderGuid        Points to the identifir of credential provider.\r
2000   @param[in]  OpCodeHandle        Points to container for dynamic created opcodes.\r
2001 \r
2002 **/\r
2003 VOID\r
2004 AddProviderSelection (\r
2005   IN     EFI_GUID                               *ProviderGuid,\r
2006   IN     VOID                                   *OpCodeHandle\r
2007   )\r
2008 {\r
2009   EFI_HII_HANDLE                HiiHandle;\r
2010   EFI_STRING_ID                 ProvID;\r
2011   CHAR16                        *ProvStr;\r
2012   UINTN                         Index;\r
2013   EFI_USER_CREDENTIAL2_PROTOCOL *UserCredential;\r
2014 \r
2015   for (Index = 0; Index < mProviderDb->Count; Index++) {\r
2016     UserCredential = mProviderDb->Provider[Index];\r
2017     if (CompareGuid (&UserCredential->Identifier, ProviderGuid)) {\r
2018       //\r
2019       // Add credential provider selection.\r
2020       //\r
2021       UserCredential->Title (UserCredential, &HiiHandle, &ProvID);\r
2022       ProvStr = HiiGetString (HiiHandle, ProvID, NULL);\r
2023       if (ProvStr == NULL) {\r
2024         continue ;\r
2025       }\r
2026       ProvID  = HiiSetString (mCallbackInfo->HiiHandle, 0, ProvStr, NULL);\r
2027       FreePool (ProvStr);\r
2028       HiiCreateActionOpCode (\r
2029         OpCodeHandle,                          // Container for dynamic created opcodes\r
2030         (EFI_QUESTION_ID)(LABEL_PROVIDER_NAME + Index),  // Question ID\r
2031         ProvID,                                // Prompt text\r
2032         STRING_TOKEN (STR_NULL_STRING),        // Help text\r
2033         EFI_IFR_FLAG_CALLBACK,                 // Question flag\r
2034         0                                      // Action String ID\r
2035         );\r
2036       break;\r
2037     }\r
2038   }\r
2039 }\r
2040 \r
2041 \r
2042 /**\r
2043   Add a username item in form.\r
2044 \r
2045   @param[in]  Index            The index of the user in the user name list.\r
2046   @param[in]  User             Points to the user profile whose username is added.\r
2047   @param[in]  OpCodeHandle     Points to container for dynamic created opcodes.\r
2048 \r
2049   @retval EFI_SUCCESS          Add a username successfully.\r
2050   @retval Others               Fail to add a username.\r
2051 \r
2052 **/\r
2053 EFI_STATUS\r
2054 AddUserSelection (\r
2055   IN     UINT16                                 Index,\r
2056   IN     USER_PROFILE_ENTRY                     *User,\r
2057   IN     VOID                                   *OpCodeHandle\r
2058   )\r
2059 {\r
2060   EFI_STRING_ID UserName;\r
2061   EFI_STATUS    Status;\r
2062   EFI_USER_INFO *UserInfo;\r
2063 \r
2064   UserInfo  = NULL;\r
2065   Status    = FindUserInfoByType (User, &UserInfo, EFI_USER_INFO_NAME_RECORD);\r
2066   if (EFI_ERROR (Status)) {\r
2067     return Status;\r
2068   }\r
2069 \r
2070   //\r
2071   // Add user name selection.\r
2072   //\r
2073   UserName = HiiSetString (mCallbackInfo->HiiHandle, 0, (EFI_STRING) (UserInfo + 1), NULL);\r
2074   if (UserName == 0) {\r
2075     return EFI_OUT_OF_RESOURCES;\r
2076   }\r
2077 \r
2078   HiiCreateGotoOpCode (\r
2079     OpCodeHandle,                   // Container for dynamic created opcodes\r
2080     FORMID_PROVIDER_FORM,           // Target Form ID\r
2081     UserName,                       // Prompt text\r
2082     STRING_TOKEN (STR_NULL_STRING), // Help text\r
2083     EFI_IFR_FLAG_CALLBACK,          // Question flag\r
2084     (UINT16) Index                  // Question ID\r
2085     );\r
2086 \r
2087   return EFI_SUCCESS;\r
2088 }\r
2089 \r
2090 \r
2091 /**\r
2092   Identify the user whose identity policy does not contain the operator 'OR'.\r
2093 \r
2094   @param[in]  User             Points to the user profile.\r
2095 \r
2096   @retval EFI_SUCCESS          The specified user is identified successfully.\r
2097   @retval Others               Fail to identify the user.\r
2098 \r
2099 **/\r
2100 EFI_STATUS\r
2101 IdentifyAndTypeUser (\r
2102   IN  USER_PROFILE_ENTRY                        *User\r
2103   )\r
2104 {\r
2105   EFI_STATUS                    Status;\r
2106   EFI_USER_INFO                 *IdentifyInfo;\r
2107   BOOLEAN                       Success;\r
2108   UINTN                         TotalLen;\r
2109   UINTN                         ValueLen;\r
2110   EFI_USER_INFO_IDENTITY_POLICY *Identity;\r
2111 \r
2112   //\r
2113   // Get user identify policy information.\r
2114   //\r
2115   IdentifyInfo  = NULL;\r
2116   Status        = FindUserInfoByType (User, &IdentifyInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);\r
2117   if (EFI_ERROR (Status)) {\r
2118     return Status;\r
2119   }\r
2120   ASSERT (IdentifyInfo != NULL);\r
2121 \r
2122   //\r
2123   // Check each part of identification policy expression.\r
2124   //\r
2125   Success   = FALSE;\r
2126   TotalLen  = 0;\r
2127   while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) {\r
2128     Identity  = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen);\r
2129     ValueLen  = Identity->Length - sizeof (EFI_USER_INFO_IDENTITY_POLICY);\r
2130     switch (Identity->Type) {\r
2131 \r
2132     case EFI_USER_INFO_IDENTITY_FALSE:\r
2133       //\r
2134       // Check False option.\r
2135       //\r
2136       Success = FALSE;\r
2137       break;\r
2138 \r
2139     case EFI_USER_INFO_IDENTITY_TRUE:\r
2140       //\r
2141       // Check True option.\r
2142       //\r
2143       Success = TRUE;\r
2144       break;\r
2145 \r
2146     case EFI_USER_INFO_IDENTITY_NOT:\r
2147       //\r
2148       // Check negative operation.\r
2149       //\r
2150       break;\r
2151 \r
2152     case EFI_USER_INFO_IDENTITY_AND:\r
2153       //\r
2154       // Check and operation.\r
2155       //\r
2156       if (!Success) {\r
2157         return EFI_NOT_READY;\r
2158       }\r
2159 \r
2160       Success = FALSE;\r
2161       break;\r
2162 \r
2163     case EFI_USER_INFO_IDENTITY_OR:\r
2164       //\r
2165       // Check or operation.\r
2166       //\r
2167       if (Success) {\r
2168         return EFI_SUCCESS;\r
2169       }\r
2170       break;\r
2171 \r
2172     case EFI_USER_INFO_IDENTITY_CREDENTIAL_TYPE:\r
2173       //\r
2174       // Check credential provider by type.\r
2175       //\r
2176       break;\r
2177 \r
2178     case EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER:\r
2179       //\r
2180       // Check credential provider by ID.\r
2181       //\r
2182       if (ValueLen != sizeof (EFI_GUID)) {\r
2183         return EFI_INVALID_PARAMETER;\r
2184       }\r
2185 \r
2186       Status = IdentifyByProviderId (User, (EFI_GUID *) (Identity + 1));\r
2187       if (EFI_ERROR (Status)) {\r
2188         return Status;\r
2189       }\r
2190 \r
2191       Success = TRUE;\r
2192       break;\r
2193 \r
2194     default:\r
2195       return EFI_INVALID_PARAMETER;\r
2196       break;\r
2197     }\r
2198 \r
2199     TotalLen += Identity->Length;\r
2200   }\r
2201 \r
2202   if (TotalLen != IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) {\r
2203     return EFI_INVALID_PARAMETER;\r
2204   }\r
2205 \r
2206   if (!Success) {\r
2207     return EFI_NOT_READY;\r
2208   }\r
2209 \r
2210   return EFI_SUCCESS;\r
2211 }\r
2212 \r
2213 \r
2214 /**\r
2215   Identify the user whose identity policy does not contain the operator 'AND'.\r
2216 \r
2217   @param[in]  User             Points to the user profile.\r
2218 \r
2219   @retval EFI_SUCCESS          The specified user is identified successfully.\r
2220   @retval Others               Fail to identify the user.\r
2221 \r
2222 **/\r
2223 EFI_STATUS\r
2224 IdentifyOrTypeUser (\r
2225   IN  USER_PROFILE_ENTRY                        *User\r
2226   )\r
2227 {\r
2228   EFI_STATUS                    Status;\r
2229   EFI_USER_INFO                 *IdentifyInfo;\r
2230   UINTN                         TotalLen;\r
2231   UINTN                         ValueLen;\r
2232   EFI_USER_INFO_IDENTITY_POLICY *Identity;\r
2233   VOID                          *StartOpCodeHandle;\r
2234   VOID                          *EndOpCodeHandle;\r
2235   EFI_IFR_GUID_LABEL            *StartLabel;\r
2236   EFI_IFR_GUID_LABEL            *EndLabel;\r
2237 \r
2238   //\r
2239   // Get user identify policy information.\r
2240   //\r
2241   IdentifyInfo  = NULL;\r
2242   Status        = FindUserInfoByType (User, &IdentifyInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);\r
2243   if (EFI_ERROR (Status)) {\r
2244     return Status;\r
2245   }\r
2246   ASSERT (IdentifyInfo != NULL);\r
2247 \r
2248   //\r
2249   // Initialize the container for dynamic opcodes.\r
2250   //\r
2251   StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
2252   ASSERT (StartOpCodeHandle != NULL);\r
2253 \r
2254   EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
2255   ASSERT (EndOpCodeHandle != NULL);\r
2256 \r
2257   //\r
2258   // Create Hii Extend Label OpCode.\r
2259   //\r
2260   StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
2261                                         StartOpCodeHandle,\r
2262                                         &gEfiIfrTianoGuid,\r
2263                                         NULL,\r
2264                                         sizeof (EFI_IFR_GUID_LABEL)\r
2265                                         );\r
2266   StartLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
2267   StartLabel->Number        = LABEL_PROVIDER_NAME;\r
2268 \r
2269   EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
2270                                       EndOpCodeHandle,\r
2271                                       &gEfiIfrTianoGuid,\r
2272                                       NULL,\r
2273                                       sizeof (EFI_IFR_GUID_LABEL)\r
2274                                       );\r
2275   EndLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
2276   EndLabel->Number        = LABEL_END;\r
2277 \r
2278   //\r
2279   // Add the providers that exists in the user's policy.\r
2280   //\r
2281   TotalLen = 0;\r
2282   while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) {\r
2283     Identity  = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen);\r
2284     ValueLen  = Identity->Length - sizeof (EFI_USER_INFO_IDENTITY_POLICY);\r
2285     if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) {\r
2286       AddProviderSelection ((EFI_GUID *) (Identity + 1), StartOpCodeHandle);\r
2287     }\r
2288 \r
2289     TotalLen += Identity->Length;\r
2290   }\r
2291 \r
2292   HiiUpdateForm (\r
2293     mCallbackInfo->HiiHandle, // HII handle\r
2294     &gUserIdentifyManagerGuid,// Formset GUID\r
2295     FORMID_PROVIDER_FORM,     // Form ID\r
2296     StartOpCodeHandle,        // Label for where to insert opcodes\r
2297     EndOpCodeHandle           // Replace data\r
2298     );\r
2299 \r
2300   HiiFreeOpCodeHandle (StartOpCodeHandle);\r
2301   HiiFreeOpCodeHandle (EndOpCodeHandle);\r
2302 \r
2303   return EFI_SUCCESS;\r
2304 }\r
2305 \r
2306 \r
2307 /**\r
2308   This function processes the results of changes in configuration.\r
2309 \r
2310   @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
2311   @param  Action                 Specifies the type of action taken by the browser.\r
2312   @param  QuestionId             A unique value which is sent to the original\r
2313                                  exporting driver so that it can identify the type\r
2314                                  of data to expect.\r
2315   @param  Type                   The type of value for the question.\r
2316   @param  Value                  A pointer to the data being sent to the original\r
2317                                  exporting driver.\r
2318   @param  ActionRequest          On return, points to the action requested by the\r
2319                                  callback function.\r
2320 \r
2321   @retval EFI_SUCCESS            The callback successfully handled the action.\r
2322   @retval Others                 Fail to handle the action.\r
2323 \r
2324 **/\r
2325 EFI_STATUS\r
2326 EFIAPI\r
2327 UserIdentifyManagerCallback (\r
2328   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL      *This,\r
2329   IN  EFI_BROWSER_ACTION                        Action,\r
2330   IN  EFI_QUESTION_ID                           QuestionId,\r
2331   IN  UINT8                                     Type,\r
2332   IN  EFI_IFR_TYPE_VALUE                        *Value,\r
2333   OUT EFI_BROWSER_ACTION_REQUEST                *ActionRequest\r
2334   )\r
2335 {\r
2336   EFI_STATUS              Status;\r
2337   USER_PROFILE_ENTRY      *User;\r
2338   UINT8                   PolicyType;\r
2339   UINT16                  Index;\r
2340   VOID                    *StartOpCodeHandle;\r
2341   VOID                    *EndOpCodeHandle;\r
2342   EFI_IFR_GUID_LABEL      *StartLabel;\r
2343   EFI_IFR_GUID_LABEL      *EndLabel;\r
2344 \r
2345   Status = EFI_SUCCESS;\r
2346 \r
2347   switch (Action) {\r
2348   case EFI_BROWSER_ACTION_FORM_OPEN:\r
2349     {\r
2350       //\r
2351       // Update user Form when user Form is opened.\r
2352       // This will be done only in FORM_OPEN CallBack of question with FORM_OPEN_QUESTION_ID from user Form.\r
2353       //\r
2354       if (QuestionId != FORM_OPEN_QUESTION_ID) {\r
2355         return EFI_SUCCESS;\r
2356       }\r
2357 \r
2358       //\r
2359       // Initialize the container for dynamic opcodes.\r
2360       //\r
2361       StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
2362       ASSERT (StartOpCodeHandle != NULL);\r
2363 \r
2364       EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
2365       ASSERT (EndOpCodeHandle != NULL);\r
2366 \r
2367       //\r
2368       // Create Hii Extend Label OpCode.\r
2369       //\r
2370       StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
2371                                             StartOpCodeHandle,\r
2372                                             &gEfiIfrTianoGuid,\r
2373                                             NULL,\r
2374                                             sizeof (EFI_IFR_GUID_LABEL)\r
2375                                             );\r
2376       StartLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
2377       StartLabel->Number        = LABEL_USER_NAME;\r
2378 \r
2379       EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
2380                                           EndOpCodeHandle,\r
2381                                           &gEfiIfrTianoGuid,\r
2382                                           NULL,\r
2383                                           sizeof (EFI_IFR_GUID_LABEL)\r
2384                                           );\r
2385       EndLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
2386       EndLabel->Number        = LABEL_END;\r
2387 \r
2388       //\r
2389       // Add all the user profile in the user profile database.\r
2390       //\r
2391       for (Index = 0; Index < mUserProfileDb->UserProfileNum; Index++) {\r
2392         User = (USER_PROFILE_ENTRY *) mUserProfileDb->UserProfile[Index];\r
2393         AddUserSelection ((UINT16)(LABEL_USER_NAME + Index), User, StartOpCodeHandle);\r
2394       }\r
2395 \r
2396       HiiUpdateForm (\r
2397         mCallbackInfo->HiiHandle, // HII handle\r
2398         &gUserIdentifyManagerGuid,// Formset GUID\r
2399         FORMID_USER_FORM,         // Form ID\r
2400         StartOpCodeHandle,        // Label for where to insert opcodes\r
2401         EndOpCodeHandle           // Replace data\r
2402         );\r
2403 \r
2404       HiiFreeOpCodeHandle (StartOpCodeHandle);\r
2405       HiiFreeOpCodeHandle (EndOpCodeHandle);\r
2406 \r
2407       return EFI_SUCCESS;\r
2408     }\r
2409     break;\r
2410 \r
2411   case EFI_BROWSER_ACTION_FORM_CLOSE:\r
2412     Status = EFI_SUCCESS;\r
2413     break;\r
2414 \r
2415   case EFI_BROWSER_ACTION_CHANGED:\r
2416     if (QuestionId >= LABEL_PROVIDER_NAME) {\r
2417       //\r
2418       // QuestionId comes from the second Form (Select a Credential Provider if identity\r
2419       // policy is OR type). Identify the user by the selected provider.\r
2420       //\r
2421       Status = IdentifyByProviderId (mCurrentUser, &mProviderDb->Provider[QuestionId & 0xFFF]->Identifier);\r
2422       if (Status == EFI_SUCCESS) {\r
2423         mIdentified     = TRUE;\r
2424         *ActionRequest  = EFI_BROWSER_ACTION_REQUEST_EXIT;\r
2425       }\r
2426       return EFI_SUCCESS;\r
2427     }\r
2428     break;\r
2429 \r
2430   case EFI_BROWSER_ACTION_CHANGING:\r
2431     //\r
2432     // QuestionId comes from the first Form (Select a user to identify).\r
2433     //\r
2434     if (QuestionId >= LABEL_PROVIDER_NAME) {\r
2435       return EFI_SUCCESS;\r
2436     }\r
2437 \r
2438     User   = (USER_PROFILE_ENTRY *) mUserProfileDb->UserProfile[QuestionId & 0xFFF];\r
2439     Status = GetIdentifyType (User, &PolicyType);\r
2440     if (EFI_ERROR (Status)) {\r
2441       return Status;\r
2442     }\r
2443 \r
2444     if (PolicyType == EFI_USER_INFO_IDENTITY_OR) {\r
2445       //\r
2446       // Identify the user by "OR" logical.\r
2447       //\r
2448       Status = IdentifyOrTypeUser (User);\r
2449       if (EFI_ERROR (Status)) {\r
2450         return Status;\r
2451       }\r
2452 \r
2453       mCurrentUser = (EFI_USER_PROFILE_HANDLE) User;\r
2454     } else {\r
2455       //\r
2456       // Identify the user by "AND" logical.\r
2457       //\r
2458       Status = IdentifyAndTypeUser (User);\r
2459       if (EFI_ERROR (Status)) {\r
2460         return Status;\r
2461       }\r
2462 \r
2463       mCurrentUser    = (EFI_USER_PROFILE_HANDLE) User;\r
2464       mIdentified     = TRUE;\r
2465       if (Type == EFI_IFR_TYPE_REF) {\r
2466         Value->ref.FormId = FORMID_INVALID_FORM;\r
2467       }\r
2468     }\r
2469   break;\r
2470 \r
2471   default:\r
2472     //\r
2473     // All other action return unsupported.\r
2474     //\r
2475     Status = EFI_UNSUPPORTED;\r
2476     break;\r
2477   }\r
2478 \r
2479 \r
2480   return Status;\r
2481 }\r
2482 \r
2483 \r
2484 /**\r
2485   This function construct user profile database from user data saved in the Flash.\r
2486   If no user is found in Flash, add one default user "administrator" in the user\r
2487   profile database.\r
2488 \r
2489   @retval EFI_SUCCESS            Init user profile database successfully.\r
2490   @retval Others                 Fail to init user profile database.\r
2491 \r
2492 **/\r
2493 EFI_STATUS\r
2494 InitUserProfileDb (\r
2495   VOID\r
2496   )\r
2497 {\r
2498   EFI_STATUS  Status;\r
2499   UINT8       *VarData;\r
2500   UINTN       VarSize;\r
2501   UINTN       CurVarSize;\r
2502   CHAR16      VarName[10];\r
2503   UINTN       Index;\r
2504   UINT32      VarAttr;\r
2505 \r
2506   if (mUserProfileDb != NULL) {\r
2507     //\r
2508     // The user profiles had been already initialized.\r
2509     //\r
2510     return EFI_SUCCESS;\r
2511   }\r
2512 \r
2513   //\r
2514   // Init user profile database structure.\r
2515   //\r
2516   if (!ExpandUsermUserProfileDb ()) {\r
2517     return EFI_OUT_OF_RESOURCES;\r
2518   }\r
2519 \r
2520   CurVarSize = DEFAULT_PROFILE_SIZE;\r
2521   VarData    = AllocateZeroPool (CurVarSize);\r
2522   if (VarData == NULL) {\r
2523     return EFI_OUT_OF_RESOURCES;\r
2524   }\r
2525 \r
2526   //\r
2527   // Get all user proifle entries.\r
2528   //\r
2529   Index = 0;\r
2530   while (TRUE) {\r
2531     //\r
2532     // Get variable name.\r
2533     //\r
2534     UnicodeSPrint (\r
2535       VarName,\r
2536       sizeof (VarName),\r
2537       L"User%04x",\r
2538       Index\r
2539       );\r
2540     Index++;\r
2541 \r
2542     //\r
2543     // Get variable value.\r
2544     //\r
2545     VarSize = CurVarSize;\r
2546     Status  = gRT->GetVariable (VarName, &gUserIdentifyManagerGuid, &VarAttr, &VarSize, VarData);\r
2547     if (Status == EFI_BUFFER_TOO_SMALL) {\r
2548       FreePool (VarData);\r
2549       VarData = AllocatePool (VarSize);\r
2550       if (VarData == NULL) {\r
2551         Status = EFI_OUT_OF_RESOURCES;\r
2552         break;\r
2553       }\r
2554 \r
2555       CurVarSize  = VarSize;\r
2556       Status      = gRT->GetVariable (VarName, &gUserIdentifyManagerGuid, &VarAttr, &VarSize, VarData);\r
2557     }\r
2558 \r
2559     if (EFI_ERROR (Status)) {\r
2560       if (Status == EFI_NOT_FOUND) {\r
2561         Status = EFI_SUCCESS;\r
2562       }\r
2563       break;\r
2564     }\r
2565 \r
2566     //\r
2567     // Check variable attributes.\r
2568     //\r
2569     if (VarAttr != (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS)) {\r
2570       Status = gRT->SetVariable (VarName, &gUserIdentifyManagerGuid, VarAttr, 0, NULL);\r
2571       continue;\r
2572     }\r
2573 \r
2574     //\r
2575     // Add user profile to the user profile database.\r
2576     //\r
2577     Status = AddUserProfile (NULL, VarSize, VarData, FALSE);\r
2578     if (EFI_ERROR (Status)) {\r
2579       if (Status == EFI_SECURITY_VIOLATION) {\r
2580         //\r
2581         // Delete invalid user profile\r
2582         //\r
2583         gRT->SetVariable (VarName, &gUserIdentifyManagerGuid, VarAttr, 0, NULL);\r
2584       } else if (Status == EFI_OUT_OF_RESOURCES) {\r
2585         break;\r
2586       }\r
2587     } else {\r
2588       //\r
2589       // Delete and save the profile again if some invalid profiles are deleted.\r
2590       //\r
2591       if (mUserProfileDb->UserProfileNum < Index) {\r
2592         gRT->SetVariable (VarName, &gUserIdentifyManagerGuid, VarAttr, 0, NULL);\r
2593         SaveNvUserProfile (mUserProfileDb->UserProfile[mUserProfileDb->UserProfileNum - 1], FALSE);\r
2594       }\r
2595     }\r
2596   }\r
2597 \r
2598   if (VarData != NULL) {\r
2599     FreePool (VarData);\r
2600   }\r
2601 \r
2602   if (EFI_ERROR (Status)) {\r
2603     return Status;\r
2604   }\r
2605 \r
2606   //\r
2607   // Check whether the user profile database is empty.\r
2608   //\r
2609   if (mUserProfileDb->UserProfileNum == 0) {\r
2610     Status = AddDefaultUserProfile ();\r
2611   }\r
2612 \r
2613   return Status;\r
2614 }\r
2615 \r
2616 \r
2617 /**\r
2618   This function collects all the credential providers and saves to mProviderDb.\r
2619 \r
2620   @retval EFI_SUCCESS            Collect credential providers successfully.\r
2621   @retval Others                 Fail to collect credential providers.\r
2622 \r
2623 **/\r
2624 EFI_STATUS\r
2625 InitProviderInfo (\r
2626   VOID\r
2627   )\r
2628 {\r
2629   EFI_STATUS  Status;\r
2630   UINTN       HandleCount;\r
2631   EFI_HANDLE  *HandleBuf;\r
2632   UINTN       Index;\r
2633 \r
2634   if (mProviderDb != NULL) {\r
2635     //\r
2636     // The credential providers had been collected before.\r
2637     //\r
2638     return EFI_SUCCESS;\r
2639   }\r
2640 \r
2641   //\r
2642   // Try to find all the user credential provider driver.\r
2643   //\r
2644   HandleCount = 0;\r
2645   HandleBuf   = NULL;\r
2646   Status = gBS->LocateHandleBuffer (\r
2647                   ByProtocol,\r
2648                   &gEfiUserCredential2ProtocolGuid,\r
2649                   NULL,\r
2650                   &HandleCount,\r
2651                   &HandleBuf\r
2652                   );\r
2653   if (EFI_ERROR (Status)) {\r
2654     return Status;\r
2655   }\r
2656 \r
2657   //\r
2658   // Get provider infomation.\r
2659   //\r
2660   mProviderDb = AllocateZeroPool (\r
2661                   sizeof (CREDENTIAL_PROVIDER_INFO) -\r
2662                   sizeof (EFI_USER_CREDENTIAL2_PROTOCOL *) +\r
2663                   HandleCount * sizeof (EFI_USER_CREDENTIAL2_PROTOCOL *)\r
2664                   );\r
2665   if (mProviderDb == NULL) {\r
2666     FreePool (HandleBuf);\r
2667     return EFI_OUT_OF_RESOURCES;\r
2668   }\r
2669 \r
2670  mProviderDb->Count = HandleCount;\r
2671   for (Index = 0; Index < HandleCount; Index++) {\r
2672     Status = gBS->HandleProtocol (\r
2673                     HandleBuf[Index],\r
2674                     &gEfiUserCredential2ProtocolGuid,\r
2675                     (VOID **) &mProviderDb->Provider[Index]\r
2676                     );\r
2677     if (EFI_ERROR (Status)) {\r
2678       FreePool (HandleBuf);\r
2679       FreePool (mProviderDb);\r
2680       mProviderDb = NULL;\r
2681       return Status;\r
2682     }\r
2683   }\r
2684 \r
2685   FreePool (HandleBuf);\r
2686   return EFI_SUCCESS;\r
2687 }\r
2688 \r
2689 \r
2690 /**\r
2691   This function allows a caller to extract the current configuration for one\r
2692   or more named elements from the target driver.\r
2693 \r
2694 \r
2695   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
2696   @param Request         A null-terminated Unicode string in <ConfigRequest> format.\r
2697   @param Progress        On return, points to a character in the Request string.\r
2698                          Points to the string's null terminator if request was successful.\r
2699                          Points to the most recent '&' before the first failing name/value\r
2700                          pair (or the beginning of the string if the failure is in the\r
2701                          first name/value pair) if the request was not successful.\r
2702   @param Results         A null-terminated Unicode string in <ConfigAltResp> format which\r
2703                          has all values filled in for the names in the Request string.\r
2704                          String to be allocated by the called function.\r
2705 \r
2706   @retval  EFI_SUCCESS            The Results is filled with the requested values.\r
2707   @retval  EFI_OUT_OF_RESOURCES   Not enough memory to store the results.\r
2708   @retval  EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.\r
2709   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.\r
2710 \r
2711 **/\r
2712 EFI_STATUS\r
2713 EFIAPI\r
2714 FakeExtractConfig (\r
2715   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
2716   IN  CONST EFI_STRING                       Request,\r
2717   OUT EFI_STRING                             *Progress,\r
2718   OUT EFI_STRING                             *Results\r
2719   )\r
2720 {\r
2721   if (Progress == NULL || Results == NULL) {\r
2722     return EFI_INVALID_PARAMETER;\r
2723   }\r
2724   *Progress = Request;\r
2725   return EFI_NOT_FOUND;\r
2726 }\r
2727 \r
2728 /**\r
2729   This function processes the results of changes in configuration.\r
2730 \r
2731 \r
2732   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
2733   @param Configuration   A null-terminated Unicode string in <ConfigResp> format.\r
2734   @param Progress        A pointer to a string filled in with the offset of the most\r
2735                          recent '&' before the first failing name/value pair (or the\r
2736                          beginning of the string if the failure is in the first\r
2737                          name/value pair) or the terminating NULL if all was successful.\r
2738 \r
2739   @retval  EFI_SUCCESS            The Results is processed successfully.\r
2740   @retval  EFI_INVALID_PARAMETER  Configuration is NULL.\r
2741   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.\r
2742 \r
2743 **/\r
2744 EFI_STATUS\r
2745 EFIAPI\r
2746 FakeRouteConfig (\r
2747   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
2748   IN  CONST EFI_STRING                       Configuration,\r
2749   OUT EFI_STRING                             *Progress\r
2750   )\r
2751 {\r
2752   if (Configuration == NULL || Progress == NULL) {\r
2753     return EFI_INVALID_PARAMETER;\r
2754   }\r
2755 \r
2756   *Progress = Configuration;\r
2757 \r
2758   return EFI_NOT_FOUND;\r
2759 }\r
2760 \r
2761 \r
2762 /**\r
2763   This function initialize the data mainly used in form browser.\r
2764 \r
2765   @retval EFI_SUCCESS          Initialize form data successfully.\r
2766   @retval Others               Fail to Initialize form data.\r
2767 \r
2768 **/\r
2769 EFI_STATUS\r
2770 InitFormBrowser (\r
2771   VOID\r
2772   )\r
2773 {\r
2774   EFI_STATUS                  Status;\r
2775   USER_MANAGER_CALLBACK_INFO  *CallbackInfo;\r
2776   EFI_HII_DATABASE_PROTOCOL   *HiiDatabase;\r
2777   EFI_HII_STRING_PROTOCOL     *HiiString;\r
2778   EFI_FORM_BROWSER2_PROTOCOL  *FormBrowser2;\r
2779 \r
2780   //\r
2781   // Initialize driver private data.\r
2782   //\r
2783   CallbackInfo = AllocateZeroPool (sizeof (USER_MANAGER_CALLBACK_INFO));\r
2784   if (CallbackInfo == NULL) {\r
2785     return EFI_OUT_OF_RESOURCES;\r
2786   }\r
2787 \r
2788   CallbackInfo->Signature                   = USER_MANAGER_SIGNATURE;\r
2789   CallbackInfo->ConfigAccess.ExtractConfig  = FakeExtractConfig;\r
2790   CallbackInfo->ConfigAccess.RouteConfig    = FakeRouteConfig;\r
2791   CallbackInfo->ConfigAccess.Callback       = UserIdentifyManagerCallback;\r
2792 \r
2793   //\r
2794   // Locate Hii Database protocol.\r
2795   //\r
2796   Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &HiiDatabase);\r
2797   if (EFI_ERROR (Status)) {\r
2798     return Status;\r
2799   }\r
2800   CallbackInfo->HiiDatabase = HiiDatabase;\r
2801 \r
2802   //\r
2803   // Locate HiiString protocol.\r
2804   //\r
2805   Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &HiiString);\r
2806   if (EFI_ERROR (Status)) {\r
2807     return Status;\r
2808   }\r
2809   CallbackInfo->HiiString = HiiString;\r
2810 \r
2811   //\r
2812   // Locate Formbrowser2 protocol.\r
2813   //\r
2814   Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);\r
2815   if (EFI_ERROR (Status)) {\r
2816     return Status;\r
2817   }\r
2818 \r
2819   CallbackInfo->FormBrowser2  = FormBrowser2;\r
2820   CallbackInfo->DriverHandle  = NULL;\r
2821 \r
2822   //\r
2823   // Install Device Path Protocol and Config Access protocol to driver handle.\r
2824   //\r
2825   Status = gBS->InstallMultipleProtocolInterfaces (\r
2826                   &CallbackInfo->DriverHandle,\r
2827                   &gEfiDevicePathProtocolGuid,\r
2828                   &mHiiVendorDevicePath,\r
2829                   &gEfiHiiConfigAccessProtocolGuid,\r
2830                   &CallbackInfo->ConfigAccess,\r
2831                   NULL\r
2832                   );\r
2833   ASSERT_EFI_ERROR (Status);\r
2834 \r
2835   //\r
2836   // Publish HII data.\r
2837   //\r
2838   CallbackInfo->HiiHandle = HiiAddPackages (\r
2839                               &gUserIdentifyManagerGuid,\r
2840                               CallbackInfo->DriverHandle,\r
2841                               UserIdentifyManagerStrings,\r
2842                               UserIdentifyManagerVfrBin,\r
2843                               NULL\r
2844                               );\r
2845   if (CallbackInfo->HiiHandle == NULL) {\r
2846     return EFI_OUT_OF_RESOURCES;\r
2847   }\r
2848 \r
2849   mCallbackInfo = CallbackInfo;\r
2850 \r
2851   return EFI_SUCCESS;\r
2852 }\r
2853 \r
2854 \r
2855 /**\r
2856   Identify the user whose identification policy supports auto logon.\r
2857 \r
2858   @param[in]   ProviderIndex   The provider index in the provider list.\r
2859   @param[out]  User            Points to user user profile if a user is identified successfully.\r
2860 \r
2861   @retval EFI_SUCCESS          Identify a user with the specified provider successfully.\r
2862   @retval Others               Fail to identify a user.\r
2863 \r
2864 **/\r
2865 EFI_STATUS\r
2866 IdentifyAutoLogonUser (\r
2867   IN  UINTN                                     ProviderIndex,\r
2868   OUT USER_PROFILE_ENTRY                        **User\r
2869   )\r
2870 {\r
2871   EFI_STATUS    Status;\r
2872   EFI_USER_INFO *Info;\r
2873   UINT8         PolicyType;\r
2874 \r
2875   Info = AllocateZeroPool (sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_IDENTIFIER));\r
2876   if (Info == NULL) {\r
2877     return EFI_OUT_OF_RESOURCES;\r
2878   }\r
2879 \r
2880   Info->InfoType  = EFI_USER_INFO_IDENTIFIER_RECORD;\r
2881   Info->InfoSize  = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_IDENTIFIER);\r
2882 \r
2883   //\r
2884   // Identify the specified credential provider's auto logon user.\r
2885   //\r
2886   Status = mProviderDb->Provider[ProviderIndex]->User (\r
2887                                                    mProviderDb->Provider[ProviderIndex],\r
2888                                                    NULL,\r
2889                                                    (EFI_USER_INFO_IDENTIFIER *) (Info + 1)\r