1 /** @file
2   Internal file explorer functions for SecureBoot configuration module.
3 
4 Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution.  The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9 
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "SecureBootConfigImpl.h"
16 
17 VOID                  *mStartOpCodeHandle = NULL;
18 VOID                  *mEndOpCodeHandle = NULL;
19 EFI_IFR_GUID_LABEL    *mStartLabel = NULL;
20 EFI_IFR_GUID_LABEL    *mEndLabel = NULL;
21 
22 /**
23   Refresh the global UpdateData structure.
24 
25 **/
26 VOID
RefreshUpdateData(VOID)27 RefreshUpdateData (
28   VOID
29   )
30 {
31   //
32   // Free current updated date
33   //
34   if (mStartOpCodeHandle != NULL) {
35     HiiFreeOpCodeHandle (mStartOpCodeHandle);
36   }
37 
38   //
39   // Create new OpCode Handle
40   //
41   mStartOpCodeHandle = HiiAllocateOpCodeHandle ();
42 
43   //
44   // Create Hii Extend Label OpCode as the start opcode
45   //
46   mStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
47                                          mStartOpCodeHandle,
48                                          &gEfiIfrTianoGuid,
49                                          NULL,
50                                          sizeof (EFI_IFR_GUID_LABEL)
51                                          );
52   mStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
53 }
54 
55 /**
56   Clean up the dynamic opcode at label and form specified by both LabelId.
57 
58   @param[in] LabelId         It is both the Form ID and Label ID for opcode deletion.
59   @param[in] PrivateData     Module private data.
60 
61 **/
62 VOID
CleanUpPage(IN UINT16 LabelId,IN SECUREBOOT_CONFIG_PRIVATE_DATA * PrivateData)63 CleanUpPage (
64   IN UINT16                           LabelId,
65   IN SECUREBOOT_CONFIG_PRIVATE_DATA   *PrivateData
66   )
67 {
68   RefreshUpdateData ();
69 
70   //
71   // Remove all op-codes from dynamic page
72   //
73   mStartLabel->Number = LabelId;
74   HiiUpdateForm (
75     PrivateData->HiiHandle,
76     &gSecureBootConfigFormSetGuid,
77     LabelId,
78     mStartOpCodeHandle, // Label LabelId
79     mEndOpCodeHandle    // LABEL_END
80     );
81 }
82 
83 /**
84   This function will open a file or directory referenced by DevicePath.
85 
86   This function opens a file with the open mode according to the file path. The
87   Attributes is valid only for EFI_FILE_MODE_CREATE.
88 
89   @param[in, out]  FilePath        On input, the device path to the file.
90                                    On output, the remaining device path.
91   @param[out]      FileHandle      Pointer to the file handle.
92   @param[in]       OpenMode        The mode to open the file with.
93   @param[in]       Attributes      The file's file attributes.
94 
95   @retval EFI_SUCCESS              The information was set.
96   @retval EFI_INVALID_PARAMETER    One of the parameters has an invalid value.
97   @retval EFI_UNSUPPORTED          Could not open the file path.
98   @retval EFI_NOT_FOUND            The specified file could not be found on the
99                                    device or the file system could not be found on
100                                    the device.
101   @retval EFI_NO_MEDIA             The device has no medium.
102   @retval EFI_MEDIA_CHANGED        The device has a different medium in it or the
103                                    medium is no longer supported.
104   @retval EFI_DEVICE_ERROR         The device reported an error.
105   @retval EFI_VOLUME_CORRUPTED     The file system structures are corrupted.
106   @retval EFI_WRITE_PROTECTED      The file or medium is write protected.
107   @retval EFI_ACCESS_DENIED        The file was opened read only.
108   @retval EFI_OUT_OF_RESOURCES     Not enough resources were available to open the
109                                    file.
110   @retval EFI_VOLUME_FULL          The volume is full.
111 **/
112 EFI_STATUS
113 EFIAPI
OpenFileByDevicePath(IN OUT EFI_DEVICE_PATH_PROTOCOL ** FilePath,OUT EFI_FILE_HANDLE * FileHandle,IN UINT64 OpenMode,IN UINT64 Attributes)114 OpenFileByDevicePath(
115   IN OUT EFI_DEVICE_PATH_PROTOCOL     **FilePath,
116   OUT EFI_FILE_HANDLE                 *FileHandle,
117   IN UINT64                           OpenMode,
118   IN UINT64                           Attributes
119   )
120 {
121   EFI_STATUS                      Status;
122   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol;
123   EFI_FILE_PROTOCOL               *Handle1;
124   EFI_FILE_PROTOCOL               *Handle2;
125   EFI_HANDLE                      DeviceHandle;
126 
127   if ((FilePath == NULL || FileHandle == NULL)) {
128     return EFI_INVALID_PARAMETER;
129   }
130 
131   Status = gBS->LocateDevicePath (
132                   &gEfiSimpleFileSystemProtocolGuid,
133                   FilePath,
134                   &DeviceHandle
135                   );
136   if (EFI_ERROR (Status)) {
137     return Status;
138   }
139 
140   Status = gBS->OpenProtocol(
141                   DeviceHandle,
142                   &gEfiSimpleFileSystemProtocolGuid,
143                   (VOID**)&EfiSimpleFileSystemProtocol,
144                   gImageHandle,
145                   NULL,
146                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
147                   );
148   if (EFI_ERROR (Status)) {
149     return Status;
150   }
151 
152   Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, &Handle1);
153   if (EFI_ERROR (Status)) {
154     FileHandle = NULL;
155     return Status;
156   }
157 
158   //
159   // go down directories one node at a time.
160   //
161   while (!IsDevicePathEnd (*FilePath)) {
162     //
163     // For file system access each node should be a file path component
164     //
165     if (DevicePathType    (*FilePath) != MEDIA_DEVICE_PATH ||
166         DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP
167        ) {
168       FileHandle = NULL;
169       return (EFI_INVALID_PARAMETER);
170     }
171     //
172     // Open this file path node
173     //
174     Handle2  = Handle1;
175     Handle1 = NULL;
176 
177     //
178     // Try to test opening an existing file
179     //
180     Status = Handle2->Open (
181                           Handle2,
182                           &Handle1,
183                           ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName,
184                           OpenMode &~EFI_FILE_MODE_CREATE,
185                           0
186                          );
187 
188     //
189     // see if the error was that it needs to be created
190     //
191     if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) {
192       Status = Handle2->Open (
193                             Handle2,
194                             &Handle1,
195                             ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName,
196                             OpenMode,
197                             Attributes
198                            );
199     }
200     //
201     // Close the last node
202     //
203     Handle2->Close (Handle2);
204 
205     if (EFI_ERROR(Status)) {
206       return (Status);
207     }
208 
209     //
210     // Get the next node
211     //
212     *FilePath = NextDevicePathNode (*FilePath);
213   }
214 
215   //
216   // This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also!
217   //
218   *FileHandle = (VOID*)Handle1;
219   return EFI_SUCCESS;
220 }
221 
222 
223 /**
224   Extract filename from device path. The returned buffer is allocated using AllocateCopyPool.
225   The caller is responsible for freeing the allocated buffer using FreePool(). If return NULL
226   means not enough memory resource.
227 
228   @param DevicePath       Device path.
229 
230   @retval NULL            Not enough memory resourece for AllocateCopyPool.
231   @retval Other           A new allocated string that represents the file name.
232 
233 **/
234 CHAR16 *
ExtractFileNameFromDevicePath(IN EFI_DEVICE_PATH_PROTOCOL * DevicePath)235 ExtractFileNameFromDevicePath (
236   IN   EFI_DEVICE_PATH_PROTOCOL *DevicePath
237   )
238 {
239   CHAR16          *String;
240   CHAR16          *MatchString;
241   CHAR16          *LastMatch;
242   CHAR16          *FileName;
243   UINTN           Length;
244 
245   ASSERT(DevicePath != NULL);
246 
247   String = DevicePathToStr(DevicePath);
248   MatchString = String;
249   LastMatch   = String;
250   FileName    = NULL;
251 
252   while(MatchString != NULL){
253     LastMatch   = MatchString + 1;
254     MatchString = StrStr(LastMatch,L"\\");
255   }
256 
257   Length = StrLen(LastMatch);
258   FileName = AllocateCopyPool ((Length + 1) * sizeof(CHAR16), LastMatch);
259   if (FileName != NULL) {
260     *(FileName + Length) = 0;
261   }
262 
263   FreePool(String);
264 
265   return FileName;
266 }
267 
268 
269 /**
270   Update  the form base on the selected file.
271 
272   @param FilePath   Point to the file path.
273   @param FormId     The form need to display.
274 
275   @retval TRUE   Exit caller function.
276   @retval FALSE  Not exit caller function.
277 
278 **/
279 BOOLEAN
UpdatePage(IN EFI_DEVICE_PATH_PROTOCOL * FilePath,IN EFI_FORM_ID FormId)280 UpdatePage(
281   IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath,
282   IN  EFI_FORM_ID               FormId
283   )
284 {
285   CHAR16                *FileName;
286   EFI_STRING_ID         StringToken;
287 
288   FileName = NULL;
289 
290   if (FilePath != NULL) {
291     FileName = ExtractFileNameFromDevicePath(FilePath);
292   }
293   if (FileName == NULL) {
294     //
295     // FileName = NULL has two case:
296     // 1. FilePath == NULL, not select file.
297     // 2. FilePath != NULL, but ExtractFileNameFromDevicePath return NULL not enough memory resource.
298     // In these two case, no need to update the form, and exit the caller function.
299     //
300     return TRUE;
301   }
302   StringToken =  HiiSetString (gSecureBootPrivateData->HiiHandle, 0, FileName, NULL);
303 
304   gSecureBootPrivateData->FileContext->FileName = FileName;
305 
306   OpenFileByDevicePath(
307     &FilePath,
308     &gSecureBootPrivateData->FileContext->FHandle,
309     EFI_FILE_MODE_READ,
310     0
311     );
312   //
313   // Create Subtitle op-code for the display string of the option.
314   //
315   RefreshUpdateData ();
316   mStartLabel->Number = FormId;
317 
318   HiiCreateSubTitleOpCode (
319     mStartOpCodeHandle,
320     StringToken,
321     0,
322     0,
323     0
324    );
325 
326   HiiUpdateForm (
327     gSecureBootPrivateData->HiiHandle,
328     &gSecureBootConfigFormSetGuid,
329     FormId,
330     mStartOpCodeHandle, // Label FormId
331     mEndOpCodeHandle    // LABEL_END
332     );
333 
334   return TRUE;
335 }
336 
337 /**
338   Update the PK form base on the input file path info.
339 
340   @param FilePath    Point to the file path.
341 
342   @retval TRUE   Exit caller function.
343   @retval FALSE  Not exit caller function.
344 **/
345 BOOLEAN
346 EFIAPI
UpdatePKFromFile(IN EFI_DEVICE_PATH_PROTOCOL * FilePath)347 UpdatePKFromFile (
348   IN EFI_DEVICE_PATH_PROTOCOL    *FilePath
349   )
350 {
351   return UpdatePage(FilePath, FORMID_ENROLL_PK_FORM);
352 
353 }
354 
355 /**
356   Update the KEK form base on the input file path info.
357 
358   @param FilePath    Point to the file path.
359 
360   @retval TRUE   Exit caller function.
361   @retval FALSE  Not exit caller function.
362 **/
363 BOOLEAN
364 EFIAPI
UpdateKEKFromFile(IN EFI_DEVICE_PATH_PROTOCOL * FilePath)365 UpdateKEKFromFile (
366   IN EFI_DEVICE_PATH_PROTOCOL    *FilePath
367   )
368 {
369   return UpdatePage(FilePath, FORMID_ENROLL_KEK_FORM);
370 }
371 
372 /**
373   Update the DB form base on the input file path info.
374 
375   @param FilePath    Point to the file path.
376 
377   @retval TRUE   Exit caller function.
378   @retval FALSE  Not exit caller function.
379 **/
380 BOOLEAN
381 EFIAPI
UpdateDBFromFile(IN EFI_DEVICE_PATH_PROTOCOL * FilePath)382 UpdateDBFromFile (
383   IN EFI_DEVICE_PATH_PROTOCOL    *FilePath
384   )
385 {
386   return UpdatePage(FilePath, SECUREBOOT_ENROLL_SIGNATURE_TO_DB);
387 }
388 
389 /**
390   Update the DBX form base on the input file path info.
391 
392   @param FilePath    Point to the file path.
393 
394   @retval TRUE   Exit caller function.
395   @retval FALSE  Not exit caller function.
396 **/
397 BOOLEAN
398 EFIAPI
UpdateDBXFromFile(IN EFI_DEVICE_PATH_PROTOCOL * FilePath)399 UpdateDBXFromFile (
400   IN EFI_DEVICE_PATH_PROTOCOL    *FilePath
401   )
402 {
403   return UpdatePage(FilePath, SECUREBOOT_ENROLL_SIGNATURE_TO_DBX);
404 }
405 
406 /**
407   Update the DBT form base on the input file path info.
408 
409   @param FilePath    Point to the file path.
410 
411   @retval TRUE   Exit caller function.
412   @retval FALSE  Not exit caller function.
413 **/
414 BOOLEAN
415 EFIAPI
UpdateDBTFromFile(IN EFI_DEVICE_PATH_PROTOCOL * FilePath)416 UpdateDBTFromFile (
417   IN EFI_DEVICE_PATH_PROTOCOL    *FilePath
418   )
419 {
420   return UpdatePage(FilePath, SECUREBOOT_ENROLL_SIGNATURE_TO_DBT);
421 }
422 
423