| /** @file | |
| Internal file explorer functions for SecureBoot configuration module. | |
| Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "SecureBootConfigImpl.h" | |
| VOID *mStartOpCodeHandle = NULL; | |
| VOID *mEndOpCodeHandle = NULL; | |
| EFI_IFR_GUID_LABEL *mStartLabel = NULL; | |
| EFI_IFR_GUID_LABEL *mEndLabel = NULL; | |
| /** | |
| Refresh the global UpdateData structure. | |
| **/ | |
| VOID | |
| RefreshUpdateData ( | |
| VOID | |
| ) | |
| { | |
| // | |
| // Free current updated date | |
| // | |
| if (mStartOpCodeHandle != NULL) { | |
| HiiFreeOpCodeHandle (mStartOpCodeHandle); | |
| } | |
| // | |
| // Create new OpCode Handle | |
| // | |
| mStartOpCodeHandle = HiiAllocateOpCodeHandle (); | |
| // | |
| // Create Hii Extend Label OpCode as the start opcode | |
| // | |
| mStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( | |
| mStartOpCodeHandle, | |
| &gEfiIfrTianoGuid, | |
| NULL, | |
| sizeof (EFI_IFR_GUID_LABEL) | |
| ); | |
| mStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; | |
| } | |
| /** | |
| Clean up the dynamic opcode at label and form specified by both LabelId. | |
| @param[in] LabelId It is both the Form ID and Label ID for opcode deletion. | |
| @param[in] PrivateData Module private data. | |
| **/ | |
| VOID | |
| CleanUpPage ( | |
| IN UINT16 LabelId, | |
| IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData | |
| ) | |
| { | |
| RefreshUpdateData (); | |
| // | |
| // Remove all op-codes from dynamic page | |
| // | |
| mStartLabel->Number = LabelId; | |
| HiiUpdateForm ( | |
| PrivateData->HiiHandle, | |
| &gSecureBootConfigFormSetGuid, | |
| LabelId, | |
| mStartOpCodeHandle, // Label LabelId | |
| mEndOpCodeHandle // LABEL_END | |
| ); | |
| } | |
| /** | |
| This function will open a file or directory referenced by DevicePath. | |
| This function opens a file with the open mode according to the file path. The | |
| Attributes is valid only for EFI_FILE_MODE_CREATE. | |
| @param[in, out] FilePath On input, the device path to the file. | |
| On output, the remaining device path. | |
| @param[out] FileHandle Pointer to the file handle. | |
| @param[in] OpenMode The mode to open the file with. | |
| @param[in] Attributes The file's file attributes. | |
| @retval EFI_SUCCESS The information was set. | |
| @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. | |
| @retval EFI_UNSUPPORTED Could not open the file path. | |
| @retval EFI_NOT_FOUND The specified file could not be found on the | |
| device or the file system could not be found on | |
| the device. | |
| @retval EFI_NO_MEDIA The device has no medium. | |
| @retval EFI_MEDIA_CHANGED The device has a different medium in it or the | |
| medium is no longer supported. | |
| @retval EFI_DEVICE_ERROR The device reported an error. | |
| @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. | |
| @retval EFI_WRITE_PROTECTED The file or medium is write protected. | |
| @retval EFI_ACCESS_DENIED The file was opened read only. | |
| @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the | |
| file. | |
| @retval EFI_VOLUME_FULL The volume is full. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| OpenFileByDevicePath( | |
| IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, | |
| OUT EFI_FILE_HANDLE *FileHandle, | |
| IN UINT64 OpenMode, | |
| IN UINT64 Attributes | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol; | |
| EFI_FILE_PROTOCOL *Handle1; | |
| EFI_FILE_PROTOCOL *Handle2; | |
| EFI_HANDLE DeviceHandle; | |
| if ((FilePath == NULL || FileHandle == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = gBS->LocateDevicePath ( | |
| &gEfiSimpleFileSystemProtocolGuid, | |
| FilePath, | |
| &DeviceHandle | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| Status = gBS->OpenProtocol( | |
| DeviceHandle, | |
| &gEfiSimpleFileSystemProtocolGuid, | |
| (VOID**)&EfiSimpleFileSystemProtocol, | |
| gImageHandle, | |
| NULL, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, &Handle1); | |
| if (EFI_ERROR (Status)) { | |
| FileHandle = NULL; | |
| return Status; | |
| } | |
| // | |
| // go down directories one node at a time. | |
| // | |
| while (!IsDevicePathEnd (*FilePath)) { | |
| // | |
| // For file system access each node should be a file path component | |
| // | |
| if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH || | |
| DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP | |
| ) { | |
| FileHandle = NULL; | |
| return (EFI_INVALID_PARAMETER); | |
| } | |
| // | |
| // Open this file path node | |
| // | |
| Handle2 = Handle1; | |
| Handle1 = NULL; | |
| // | |
| // Try to test opening an existing file | |
| // | |
| Status = Handle2->Open ( | |
| Handle2, | |
| &Handle1, | |
| ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName, | |
| OpenMode &~EFI_FILE_MODE_CREATE, | |
| 0 | |
| ); | |
| // | |
| // see if the error was that it needs to be created | |
| // | |
| if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) { | |
| Status = Handle2->Open ( | |
| Handle2, | |
| &Handle1, | |
| ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName, | |
| OpenMode, | |
| Attributes | |
| ); | |
| } | |
| // | |
| // Close the last node | |
| // | |
| Handle2->Close (Handle2); | |
| if (EFI_ERROR(Status)) { | |
| return (Status); | |
| } | |
| // | |
| // Get the next node | |
| // | |
| *FilePath = NextDevicePathNode (*FilePath); | |
| } | |
| // | |
| // This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also! | |
| // | |
| *FileHandle = (VOID*)Handle1; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Extract filename from device path. The returned buffer is allocated using AllocateCopyPool. | |
| The caller is responsible for freeing the allocated buffer using FreePool(). If return NULL | |
| means not enough memory resource. | |
| @param DevicePath Device path. | |
| @retval NULL Not enough memory resourece for AllocateCopyPool. | |
| @retval Other A new allocated string that represents the file name. | |
| **/ | |
| CHAR16 * | |
| ExtractFileNameFromDevicePath ( | |
| IN EFI_DEVICE_PATH_PROTOCOL *DevicePath | |
| ) | |
| { | |
| CHAR16 *String; | |
| CHAR16 *MatchString; | |
| CHAR16 *LastMatch; | |
| CHAR16 *FileName; | |
| UINTN Length; | |
| ASSERT(DevicePath != NULL); | |
| String = DevicePathToStr(DevicePath); | |
| MatchString = String; | |
| LastMatch = String; | |
| FileName = NULL; | |
| while(MatchString != NULL){ | |
| LastMatch = MatchString + 1; | |
| MatchString = StrStr(LastMatch,L"\\"); | |
| } | |
| Length = StrLen(LastMatch); | |
| FileName = AllocateCopyPool ((Length + 1) * sizeof(CHAR16), LastMatch); | |
| if (FileName != NULL) { | |
| *(FileName + Length) = 0; | |
| } | |
| FreePool(String); | |
| return FileName; | |
| } | |
| /** | |
| Update the form base on the selected file. | |
| @param FilePath Point to the file path. | |
| @param FormId The form need to display. | |
| @retval TRUE Exit caller function. | |
| @retval FALSE Not exit caller function. | |
| **/ | |
| BOOLEAN | |
| UpdatePage( | |
| IN EFI_DEVICE_PATH_PROTOCOL *FilePath, | |
| IN EFI_FORM_ID FormId | |
| ) | |
| { | |
| CHAR16 *FileName; | |
| EFI_STRING_ID StringToken; | |
| FileName = NULL; | |
| if (FilePath != NULL) { | |
| FileName = ExtractFileNameFromDevicePath(FilePath); | |
| } | |
| if (FileName == NULL) { | |
| // | |
| // FileName = NULL has two case: | |
| // 1. FilePath == NULL, not select file. | |
| // 2. FilePath != NULL, but ExtractFileNameFromDevicePath return NULL not enough memory resource. | |
| // In these two case, no need to update the form, and exit the caller function. | |
| // | |
| return TRUE; | |
| } | |
| StringToken = HiiSetString (gSecureBootPrivateData->HiiHandle, 0, FileName, NULL); | |
| gSecureBootPrivateData->FileContext->FileName = FileName; | |
| OpenFileByDevicePath( | |
| &FilePath, | |
| &gSecureBootPrivateData->FileContext->FHandle, | |
| EFI_FILE_MODE_READ, | |
| 0 | |
| ); | |
| // | |
| // Create Subtitle op-code for the display string of the option. | |
| // | |
| RefreshUpdateData (); | |
| mStartLabel->Number = FormId; | |
| HiiCreateSubTitleOpCode ( | |
| mStartOpCodeHandle, | |
| StringToken, | |
| 0, | |
| 0, | |
| 0 | |
| ); | |
| HiiUpdateForm ( | |
| gSecureBootPrivateData->HiiHandle, | |
| &gSecureBootConfigFormSetGuid, | |
| FormId, | |
| mStartOpCodeHandle, // Label FormId | |
| mEndOpCodeHandle // LABEL_END | |
| ); | |
| return TRUE; | |
| } | |
| /** | |
| Update the PK form base on the input file path info. | |
| @param FilePath Point to the file path. | |
| @retval TRUE Exit caller function. | |
| @retval FALSE Not exit caller function. | |
| **/ | |
| BOOLEAN | |
| EFIAPI | |
| UpdatePKFromFile ( | |
| IN EFI_DEVICE_PATH_PROTOCOL *FilePath | |
| ) | |
| { | |
| return UpdatePage(FilePath, FORMID_ENROLL_PK_FORM); | |
| } | |
| /** | |
| Update the KEK form base on the input file path info. | |
| @param FilePath Point to the file path. | |
| @retval TRUE Exit caller function. | |
| @retval FALSE Not exit caller function. | |
| **/ | |
| BOOLEAN | |
| EFIAPI | |
| UpdateKEKFromFile ( | |
| IN EFI_DEVICE_PATH_PROTOCOL *FilePath | |
| ) | |
| { | |
| return UpdatePage(FilePath, FORMID_ENROLL_KEK_FORM); | |
| } | |
| /** | |
| Update the DB form base on the input file path info. | |
| @param FilePath Point to the file path. | |
| @retval TRUE Exit caller function. | |
| @retval FALSE Not exit caller function. | |
| **/ | |
| BOOLEAN | |
| EFIAPI | |
| UpdateDBFromFile ( | |
| IN EFI_DEVICE_PATH_PROTOCOL *FilePath | |
| ) | |
| { | |
| return UpdatePage(FilePath, SECUREBOOT_ENROLL_SIGNATURE_TO_DB); | |
| } | |
| /** | |
| Update the DBX form base on the input file path info. | |
| @param FilePath Point to the file path. | |
| @retval TRUE Exit caller function. | |
| @retval FALSE Not exit caller function. | |
| **/ | |
| BOOLEAN | |
| EFIAPI | |
| UpdateDBXFromFile ( | |
| IN EFI_DEVICE_PATH_PROTOCOL *FilePath | |
| ) | |
| { | |
| return UpdatePage(FilePath, SECUREBOOT_ENROLL_SIGNATURE_TO_DBX); | |
| } | |
| /** | |
| Update the DBT form base on the input file path info. | |
| @param FilePath Point to the file path. | |
| @retval TRUE Exit caller function. | |
| @retval FALSE Not exit caller function. | |
| **/ | |
| BOOLEAN | |
| EFIAPI | |
| UpdateDBTFromFile ( | |
| IN EFI_DEVICE_PATH_PROTOCOL *FilePath | |
| ) | |
| { | |
| return UpdatePage(FilePath, SECUREBOOT_ENROLL_SIGNATURE_TO_DBT); | |
| } | |