]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.c
6e5bd06502140399f023c3c1c5f348c54e6b9978
[mirror_edk2.git] / SecurityPkg / UserIdentification / UserProfileManagerDxe / UserProfileManager.c
1 /** @file
2 This driver is a configuration tool for adding, deleting or modifying user
3 profiles, including gathering the necessary information to ascertain their
4 identity in the future, updating user access policy and identification
5 policy, etc.
6
7 Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15
16 **/
17
18 #include "UserProfileManager.h"
19
20 EFI_USER_MANAGER_PROTOCOL *mUserManager = NULL;
21 CREDENTIAL_PROVIDER_INFO *mProviderInfo = NULL;
22 UINT8 mProviderChoice;
23 UINT8 mConncetLogical;
24 USER_INFO_ACCESS mAccessInfo;
25 USER_INFO mUserInfo;
26 USER_PROFILE_MANAGER_CALLBACK_INFO *mCallbackInfo;
27 HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath = {
28 {
29 {
30 HARDWARE_DEVICE_PATH,
31 HW_VENDOR_DP,
32 {
33 (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
34 (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
35 }
36 },
37 USER_PROFILE_MANAGER_GUID
38 },
39 {
40 END_DEVICE_PATH_TYPE,
41 END_ENTIRE_DEVICE_PATH_SUBTYPE,
42 {
43 (UINT8) (END_DEVICE_PATH_LENGTH),
44 (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
45 }
46 }
47 };
48
49
50 /**
51 Get string by string id from HII Interface.
52
53
54 @param[in] Id String ID to get the string from.
55
56 @retval CHAR16 * String from ID.
57 @retval NULL If error occurs.
58
59 **/
60 CHAR16 *
61 GetStringById (
62 IN EFI_STRING_ID Id
63 )
64 {
65 //
66 // Get the current string for the current Language.
67 //
68 return HiiGetString (mCallbackInfo->HiiHandle, Id, NULL);
69 }
70
71
72 /**
73 This function gets all the credential providers in the system and saved them
74 to mProviderInfo.
75
76 @retval EFI_SUCESS Init credential provider database successfully.
77 @retval Others Fail to init credential provider database.
78
79 **/
80 EFI_STATUS
81 InitProviderInfo (
82 VOID
83 )
84 {
85 EFI_STATUS Status;
86 UINTN HandleCount;
87 EFI_HANDLE *HandleBuf;
88 UINTN Index;
89
90 //
91 // Try to find all the user credential provider driver.
92 //
93 HandleCount = 0;
94 HandleBuf = NULL;
95 Status = gBS->LocateHandleBuffer (
96 ByProtocol,
97 &gEfiUserCredential2ProtocolGuid,
98 NULL,
99 &HandleCount,
100 &HandleBuf
101 );
102 if (EFI_ERROR (Status)) {
103 return Status;
104 }
105
106 //
107 // Get provider infomation.
108 //
109 if (mProviderInfo != NULL) {
110 FreePool (mProviderInfo);
111 }
112 mProviderInfo = AllocateZeroPool (
113 sizeof (CREDENTIAL_PROVIDER_INFO) -
114 sizeof (EFI_USER_CREDENTIAL2_PROTOCOL *) +
115 HandleCount * sizeof (EFI_USER_CREDENTIAL2_PROTOCOL *)
116 );
117 if (mProviderInfo == NULL) {
118 FreePool (HandleBuf);
119 return EFI_OUT_OF_RESOURCES;
120 }
121
122 mProviderInfo->Count = HandleCount;
123 for (Index = 0; Index < HandleCount; Index++) {
124 Status = gBS->HandleProtocol (
125 HandleBuf[Index],
126 &gEfiUserCredential2ProtocolGuid,
127 (VOID **) &mProviderInfo->Provider[Index]
128 );
129 if (EFI_ERROR (Status)) {
130 FreePool (HandleBuf);
131 FreePool (mProviderInfo);
132 mProviderInfo = NULL;
133 return Status;
134 }
135 }
136
137 FreePool (HandleBuf);
138 return EFI_SUCCESS;
139 }
140
141
142 /**
143 This function processes changes in user profile configuration.
144
145 @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
146 @param Action Specifies the type of action taken by the browser.
147 @param QuestionId A unique value which is sent to the original
148 exporting driver so that it can identify the type
149 of data to expect.
150 @param Type The type of value for the question.
151 @param Value A pointer to the data being sent to the original
152 exporting driver.
153 @param ActionRequest On return, points to the action requested by the
154 callback function.
155
156 @retval EFI_SUCCESS The callback successfully handled the action.
157 @retval Others Fail to handle the action.
158
159 **/
160 EFI_STATUS
161 EFIAPI
162 UserProfileManagerCallback (
163 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
164 IN EFI_BROWSER_ACTION Action,
165 IN EFI_QUESTION_ID QuestionId,
166 IN UINT8 Type,
167 IN EFI_IFR_TYPE_VALUE *Value,
168 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
169 )
170 {
171 EFI_STATUS Status;
172 EFI_INPUT_KEY Key;
173 UINT32 CurrentAccessRight;
174 CHAR16 *QuestionStr;
175 CHAR16 *PromptStr;
176 VOID *StartOpCodeHandle;
177 VOID *EndOpCodeHandle;
178 EFI_IFR_GUID_LABEL *StartLabel;
179 EFI_IFR_GUID_LABEL *EndLabel;
180 EFI_USER_PROFILE_HANDLE CurrentUser;
181
182 Status = EFI_SUCCESS;
183
184 switch (Action) {
185 case EFI_BROWSER_ACTION_FORM_OPEN:
186 {
187 //
188 // Update user manage Form when user manage Form is opened.
189 // This will be done only in FORM_OPEN CallBack of question with QUESTIONID_USER_MANAGE from user manage Form.
190 //
191 if (QuestionId != QUESTIONID_USER_MANAGE) {
192 return EFI_SUCCESS;
193 }
194
195 //
196 // Get current user
197 //
198 CurrentUser = NULL;
199 mUserManager->Current (mUserManager, &CurrentUser);
200 if (CurrentUser == NULL) {
201 DEBUG ((DEBUG_ERROR, "Error: current user does not exist!\n"));
202 return EFI_NOT_READY;
203 }
204
205 //
206 // Get current user's right information.
207 //
208 Status = GetAccessRight (&CurrentAccessRight);
209 if (EFI_ERROR (Status)) {
210 CurrentAccessRight = EFI_USER_INFO_ACCESS_ENROLL_SELF;
211 }
212
213 //
214 // Init credential provider information.
215 //
216 Status = InitProviderInfo ();
217 if (EFI_ERROR (Status)) {
218 return Status;
219 }
220
221 //
222 // Initialize the container for dynamic opcodes.
223 //
224 StartOpCodeHandle = HiiAllocateOpCodeHandle ();
225 ASSERT (StartOpCodeHandle != NULL);
226
227 EndOpCodeHandle = HiiAllocateOpCodeHandle ();
228 ASSERT (EndOpCodeHandle != NULL);
229
230 //
231 // Create Hii Extend Label OpCode.
232 //
233 StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
234 StartOpCodeHandle,
235 &gEfiIfrTianoGuid,
236 NULL,
237 sizeof (EFI_IFR_GUID_LABEL)
238 );
239 StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
240 StartLabel->Number = LABEL_USER_MANAGE_FUNC;
241
242 EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
243 EndOpCodeHandle,
244 &gEfiIfrTianoGuid,
245 NULL,
246 sizeof (EFI_IFR_GUID_LABEL)
247 );
248 EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
249 EndLabel->Number = LABEL_END;
250
251 //
252 // Add user profile option.
253 //
254 if ((CurrentAccessRight == EFI_USER_INFO_ACCESS_MANAGE) ||
255 (CurrentAccessRight == EFI_USER_INFO_ACCESS_ENROLL_OTHERS)
256 ) {
257 HiiCreateActionOpCode (
258 StartOpCodeHandle, // Container for dynamic created opcodes
259 KEY_ADD_USER, // Question ID
260 STRING_TOKEN (STR_ADD_USER_TITLE), // Prompt text
261 STRING_TOKEN (STR_ADD_USER_HELP), // Help text
262 EFI_IFR_FLAG_CALLBACK, // Question flag
263 0 // Action String ID
264 );
265 }
266
267 //
268 // Add modify user profile option.
269 //
270 HiiCreateGotoOpCode (
271 StartOpCodeHandle, // Container for dynamic created opcodes
272 FORMID_MODIFY_USER, // Target Form ID
273 STRING_TOKEN (STR_MODIFY_USER_TITLE), // Prompt text
274 STRING_TOKEN (STR_MODIFY_USER_HELP), // Help text
275 EFI_IFR_FLAG_CALLBACK, // Question flag
276 KEY_MODIFY_USER // Question ID
277 );
278
279 //
280 // Add delete user profile option
281 //
282 if (CurrentAccessRight == EFI_USER_INFO_ACCESS_MANAGE) {
283 HiiCreateGotoOpCode (
284 StartOpCodeHandle, // Container for dynamic created opcodes
285 FORMID_DEL_USER, // Target Form ID
286 STRING_TOKEN (STR_DELETE_USER_TITLE), // Prompt text
287 STRING_TOKEN (STR_DELETE_USER_HELP), // Help text
288 EFI_IFR_FLAG_CALLBACK, // Question flag
289 KEY_DEL_USER // Question ID
290 );
291 }
292
293 HiiUpdateForm (
294 mCallbackInfo->HiiHandle, // HII handle
295 &gUserProfileManagerGuid, // Formset GUID
296 FORMID_USER_MANAGE, // Form ID
297 StartOpCodeHandle, // Label for where to insert opcodes
298 EndOpCodeHandle // Replace data
299 );
300
301 HiiFreeOpCodeHandle (StartOpCodeHandle);
302 HiiFreeOpCodeHandle (EndOpCodeHandle);
303
304 return EFI_SUCCESS;
305 }
306 break;
307
308 case EFI_BROWSER_ACTION_FORM_CLOSE:
309 Status = EFI_SUCCESS;
310 break;
311
312 case EFI_BROWSER_ACTION_CHANGING:
313 {
314 //
315 // Handle the request from form.
316 //
317 if ((Value == NULL) || (ActionRequest == NULL)) {
318 return EFI_INVALID_PARAMETER;
319 }
320
321 //
322 // Judge first 2 bits.
323 //
324 switch (QuestionId & KEY_FIRST_FORM_MASK) {
325 //
326 // Add user profile operation.
327 //
328 case KEY_ADD_USER:
329 CallAddUser ();
330 break;
331
332 //
333 // Delete user profile operation.
334 //
335 case KEY_DEL_USER:
336 //
337 // Judge next 2 bits.
338 //
339 switch (QuestionId & KEY_SECOND_FORM_MASK) {
340 //
341 // Enter delete user profile form.
342 //
343 case KEY_ENTER_NEXT_FORM:
344 SelectUserToDelete ();
345 break;
346
347 //
348 // Delete specified user profile.
349 //
350 case KEY_SELECT_USER:
351 DeleteUser ((UINT8) QuestionId);
352 //
353 // Update select user form after delete a user.
354 //
355 SelectUserToDelete ();
356 break;
357
358 default:
359 break;
360 }
361 break;
362
363 //
364 // Modify user profile operation.
365 //
366 case KEY_MODIFY_USER:
367 //
368 // Judge next 2 bits.
369 //
370 switch (QuestionId & KEY_SECOND_FORM_MASK) {
371 //
372 // Enter modify user profile form.
373 //
374 case KEY_ENTER_NEXT_FORM:
375 SelectUserToModify ();
376 break;
377
378 //
379 // Enter user profile information form.
380 //
381 case KEY_SELECT_USER:
382 //
383 // Judge next 3 bits.
384 //
385 switch (QuestionId & KEY_MODIFY_INFO_MASK) {
386 //
387 // Display user information form.
388 //
389 case KEY_ENTER_NEXT_FORM:
390 ModifyUserInfo ((UINT8) QuestionId);
391 break;
392
393 //
394 // Modify user name.
395 //
396 case KEY_MODIFY_NAME:
397 ModifyUserName ();
398 //
399 // Update username in parent form.
400 //
401 SelectUserToModify ();
402 break;
403
404 //
405 // Modify identity policy.
406 //
407 case KEY_MODIFY_IP:
408 //
409 // Judge next 3 bits
410 //
411 switch (QuestionId & KEY_MODIFY_IP_MASK) {
412 //
413 // Display identity policy modify form.
414 //
415 case KEY_ENTER_NEXT_FORM:
416 ModifyIdentityPolicy ();
417 break;
418
419 //
420 // Change credential provider option.
421 //
422 case KEY_MODIFY_PROV:
423 mProviderChoice = Value->u8;
424 break;
425
426 //
427 // Change logical connector.
428 //
429 case KEY_MODIFY_CONN:
430 mConncetLogical = Value->u8;
431 break;
432
433 //
434 // Save option.
435 //
436 case KEY_ADD_IP_OP:
437 AddIdentityPolicyItem ();
438 break;
439
440 //
441 // Return to user profile information form.
442 //
443 case KEY_IP_RETURN_UIF:
444 SaveIdentityPolicy ();
445 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
446 break;
447
448 default:
449 break;
450 }
451 break;
452
453 //
454 // Modify access policy.
455 //
456 case KEY_MODIFY_AP:
457 //
458 // Judge next 3 bits.
459 //
460 switch (QuestionId & KEY_MODIFY_AP_MASK) {
461 //
462 // Display access policy modify form.
463 //
464 case KEY_ENTER_NEXT_FORM:
465 ModidyAccessPolicy ();
466 break;
467
468 //
469 // Change access right choice.
470 //
471 case KEY_MODIFY_RIGHT:
472 mAccessInfo.AccessRight = Value->u8;
473 break;
474
475 //
476 // Change setup choice.
477 //
478 case KEY_MODIFY_SETUP:
479 mAccessInfo.AccessSetup= Value->u8;
480 break;
481
482 //
483 // Change boot order choice.
484 //
485 case KEY_MODIFY_BOOT:
486 mAccessInfo.AccessBootOrder = Value->u32;
487 break;
488
489 //
490 // Load device path form.
491 //
492 case KEY_MODIFY_LOAD:
493 //
494 // Judge next 2 bits.
495 //
496 switch (QuestionId & KEY_DISPLAY_DP_MASK) {
497 //
498 // Permit load device path.
499 //
500 case KEY_PERMIT_MODIFY:
501 DisplayLoadPermit ();
502 break;
503
504 //
505 // Forbid load device path.
506 //
507 case KEY_FORBID_MODIFY:
508 DisplayLoadForbid ();
509 break;
510
511 default:
512 break;
513 }
514 break;
515
516 //
517 // Connect device path form.
518 //
519 case KEY_MODIFY_CONNECT:
520 //
521 // Judge next 2 bits.
522 //
523 switch (QuestionId & KEY_DISPLAY_DP_MASK) {
524 //
525 // Permit connect device path.
526 //
527 case KEY_PERMIT_MODIFY:
528 DisplayConnectPermit ();
529 break;
530
531 //
532 // Forbid connect device path.
533 //
534 case KEY_FORBID_MODIFY:
535 DisplayConnectForbid ();
536 break;
537
538 default:
539 break;
540 }
541 break;
542
543 //
544 // Return to user profile information form.
545 //
546 case KEY_AP_RETURN_UIF:
547 SaveAccessPolicy ();
548 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
549 break;
550
551 default:
552 break;
553 }
554 break;
555
556 default:
557 break;
558 }
559 break;
560
561 //
562 // Access policy device path modified.
563 //
564 case KEY_MODIFY_AP_DP:
565 //
566 // Judge next 2 bits.
567 //
568 switch (QuestionId & KEY_MODIFY_DP_MASK) {
569 //
570 // Load permit device path modified.
571 //
572 case KEY_LOAD_PERMIT_MODIFY:
573 QuestionStr = GetStringById (STRING_TOKEN (STR_MOVE_TO_FORBID_LIST));
574 PromptStr = GetStringById (STRING_TOKEN (STR_PRESS_KEY_CONTINUE));
575 CreatePopUp (
576 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
577 &Key,
578 QuestionStr,
579 L"",
580 PromptStr,
581 NULL
582 );
583 FreePool (QuestionStr);
584 FreePool (PromptStr);
585 if (Key.UnicodeChar != CHAR_CARRIAGE_RETURN) {
586 break;
587 }
588
589 AddToForbidLoad ((UINT16)(QuestionId & (KEY_MODIFY_DP_MASK - 1)));
590 DisplayLoadPermit ();
591 break;
592
593 //
594 // Load forbid device path modified.
595 //
596 case KEY_LOAD_FORBID_MODIFY:
597 QuestionStr = GetStringById (STRING_TOKEN (STR_MOVE_TO_PERMIT_LIST));
598 PromptStr = GetStringById (STRING_TOKEN (STR_PRESS_KEY_CONTINUE));
599 CreatePopUp (
600 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
601 &Key,
602 QuestionStr,
603 L"",
604 PromptStr,
605 NULL
606 );
607 FreePool (QuestionStr);
608 FreePool (PromptStr);
609 if (Key.UnicodeChar != CHAR_CARRIAGE_RETURN) {
610 break;
611 }
612
613 DeleteFromForbidLoad ((UINT16)(QuestionId & (KEY_MODIFY_DP_MASK - 1)));
614 DisplayLoadForbid ();
615 break;
616
617 //
618 // Connect permit device path modified.
619 //
620 case KEY_CONNECT_PERMIT_MODIFY:
621 break;
622
623 //
624 // Connect forbid device path modified.
625 //
626 case KEY_CONNECT_FORBID_MODIFY:
627 break;
628
629 default:
630 break;
631 }
632 break;
633
634 default:
635 break;
636 }
637 break;
638
639 default:
640 break;
641 }
642 }
643 break;
644
645 default:
646 //
647 // All other action return unsupported.
648 //
649 Status = EFI_UNSUPPORTED;
650 break;
651 }
652
653
654 return Status;
655 }
656
657
658 /**
659 This function allows a caller to extract the current configuration for one
660 or more named elements from the target driver.
661
662
663 @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
664 @param Request A null-terminated Unicode string in <ConfigRequest> format.
665 @param Progress On return, points to a character in the Request string.
666 Points to the string's null terminator if request was successful.
667 Points to the most recent '&' before the first failing name/value
668 pair (or the beginning of the string if the failure is in the
669 first name/value pair) if the request was not successful.
670 @param Results A null-terminated Unicode string in <ConfigAltResp> format which
671 has all values filled in for the names in the Request string.
672 String to be allocated by the called function.
673
674 @retval EFI_SUCCESS The Results is filled with the requested values.
675 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
676 @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
677 @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
678
679 **/
680 EFI_STATUS
681 EFIAPI
682 FakeExtractConfig (
683 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
684 IN CONST EFI_STRING Request,
685 OUT EFI_STRING *Progress,
686 OUT EFI_STRING *Results
687 )
688 {
689 if (Progress == NULL || Results == NULL) {
690 return EFI_INVALID_PARAMETER;
691 }
692 *Progress = Request;
693 return EFI_NOT_FOUND;
694 }
695
696 /**
697 This function processes the results of changes in configuration.
698
699
700 @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
701 @param Configuration A null-terminated Unicode string in <ConfigResp> format.
702 @param Progress A pointer to a string filled in with the offset of the most
703 recent '&' before the first failing name/value pair (or the
704 beginning of the string if the failure is in the first
705 name/value pair) or the terminating NULL if all was successful.
706
707 @retval EFI_SUCCESS The Results is processed successfully.
708 @retval EFI_INVALID_PARAMETER Configuration is NULL.
709 @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
710
711 **/
712 EFI_STATUS
713 EFIAPI
714 FakeRouteConfig (
715 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
716 IN CONST EFI_STRING Configuration,
717 OUT EFI_STRING *Progress
718 )
719 {
720 if (Configuration == NULL || Progress == NULL) {
721 return EFI_INVALID_PARAMETER;
722 }
723
724 return EFI_NOT_FOUND;
725 }
726
727
728 /**
729 Main entry for this driver.
730
731 @param ImageHandle Image handle this driver.
732 @param SystemTable Pointer to SystemTable.
733
734 @retval EFI_SUCESS This function always complete successfully.
735
736 **/
737 EFI_STATUS
738 EFIAPI
739 UserProfileManagerInit (
740 IN EFI_HANDLE ImageHandle,
741 IN EFI_SYSTEM_TABLE *SystemTable
742 )
743 {
744 EFI_STATUS Status;
745 USER_PROFILE_MANAGER_CALLBACK_INFO *CallbackInfo;
746
747 Status = gBS->LocateProtocol (
748 &gEfiUserManagerProtocolGuid,
749 NULL,
750 (VOID **) &mUserManager
751 );
752 if (EFI_ERROR (Status)) {
753 return EFI_SUCCESS;
754 }
755
756 //
757 // Initialize driver private data.
758 //
759 ZeroMem (&mUserInfo, sizeof (mUserInfo));
760 ZeroMem (&mAccessInfo, sizeof (mAccessInfo));
761
762 CallbackInfo = AllocateZeroPool (sizeof (USER_PROFILE_MANAGER_CALLBACK_INFO));
763 ASSERT (CallbackInfo != NULL);
764
765 CallbackInfo->Signature = USER_PROFILE_MANAGER_SIGNATURE;
766 CallbackInfo->ConfigAccess.ExtractConfig = FakeExtractConfig;
767 CallbackInfo->ConfigAccess.RouteConfig = FakeRouteConfig;
768 CallbackInfo->ConfigAccess.Callback = UserProfileManagerCallback;
769 CallbackInfo->DriverHandle = NULL;
770
771 //
772 // Install Device Path Protocol and Config Access protocol to driver handle.
773 //
774 Status = gBS->InstallMultipleProtocolInterfaces (
775 &CallbackInfo->DriverHandle,
776 &gEfiDevicePathProtocolGuid,
777 &mHiiVendorDevicePath,
778 &gEfiHiiConfigAccessProtocolGuid,
779 &CallbackInfo->ConfigAccess,
780 NULL
781 );
782 ASSERT_EFI_ERROR (Status);
783
784 //
785 // Publish HII data.
786 //
787 CallbackInfo->HiiHandle = HiiAddPackages (
788 &gUserProfileManagerGuid,
789 CallbackInfo->DriverHandle,
790 UserProfileManagerStrings,
791 UserProfileManagerVfrBin,
792 NULL
793 );
794 ASSERT (CallbackInfo->HiiHandle != NULL);
795 mCallbackInfo = CallbackInfo;
796
797 return Status;
798 }
799
800