Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6508 lines
184 KiB

  1. /*++
  2. Copyright (c) 1989-2001 Microsoft Corporation
  3. Module Name:
  4. sysenv.c
  5. Abstract:
  6. This module implements the NT query and set system environment
  7. variable services.
  8. Author:
  9. David N. Cutler (davec) 10-Nov-1991
  10. Revision History:
  11. --*/
  12. #include "exp.h"
  13. #pragma hdrstop
  14. #include <arccodes.h>
  15. #include <ntdddisk.h>
  16. #if defined(EFI_NVRAM_ENABLED)
  17. #include <efi.h>
  18. #include <efiboot.h>
  19. GUID ExpUnknownDeviceGuid = UNKNOWN_DEVICE_GUID;
  20. #endif
  21. #define ADD_OFFSET(_p,_o) (PVOID)((PUCHAR)(_p) + (_p)->_o)
  22. //
  23. // Signature type
  24. //
  25. typedef union _DISK_SIGNATURE_NEW {
  26. GUID Guid; // GPT disk signature
  27. ULONG Signature; // MBR disk signature
  28. } DISK_SIGNATURE_NEW, *PDISK_SIGNATURE_NEW;
  29. //
  30. // Define local subroutines.
  31. //
  32. NTSTATUS
  33. ExpSetBootEntry (
  34. IN LOGICAL CreateNewEntry,
  35. IN PBOOT_ENTRY BootEntry,
  36. OUT PULONG Id OPTIONAL
  37. );
  38. #if defined(EFI_NVRAM_ENABLED)
  39. ULONG
  40. ExpSafeWcslen (
  41. IN PWSTR String,
  42. IN PWSTR Max
  43. );
  44. NTSTATUS
  45. ExpTranslateArcPath (
  46. IN PFILE_PATH InputPath,
  47. IN ULONG OutputType,
  48. OUT PFILE_PATH OutputPath,
  49. IN OUT PULONG OutputPathLength
  50. );
  51. NTSTATUS
  52. ExpTranslateEfiPath (
  53. IN PFILE_PATH InputPath,
  54. IN ULONG OutputType,
  55. OUT PFILE_PATH OutputPath,
  56. IN OUT PULONG OutputPathLength
  57. );
  58. NTSTATUS
  59. ExpTranslateNtPath (
  60. IN PFILE_PATH InputPath,
  61. IN ULONG OutputType,
  62. OUT PFILE_PATH OutputPath,
  63. IN OUT PULONG OutputPathLength
  64. );
  65. LOGICAL
  66. ExpTranslateBootEntryNameToId (
  67. IN PWSTR Name,
  68. OUT PULONG Id
  69. );
  70. NTSTATUS
  71. ExpTranslateSymbolicLink (
  72. IN PWSTR LinkName,
  73. OUT PUNICODE_STRING ResultName
  74. );
  75. NTSTATUS
  76. ExpVerifyFilePath (
  77. PFILE_PATH FilePath,
  78. PUCHAR Max
  79. );
  80. LOGICAL
  81. ExpIsDevicePathForRemovableMedia (
  82. EFI_DEVICE_PATH *DevicePath
  83. );
  84. NTSTATUS
  85. ExpVerifyWindowsOsOptions (
  86. PWINDOWS_OS_OPTIONS WindowsOsOptions,
  87. ULONG Length
  88. );
  89. NTSTATUS
  90. ExpParseArcPathName (
  91. IN PWSTR ArcName,
  92. OUT PWSTR *ppDeviceName,
  93. OUT PWSTR *ppPathName,
  94. OUT PULONG pDeviceNameCount,
  95. OUT PBOOLEAN pSignatureFormat
  96. );
  97. NTSTATUS
  98. ExpParseSignatureName (
  99. IN PWSTR deviceName,
  100. IN ULONG deviceNameCount,
  101. OUT PDISK_SIGNATURE_NEW diskSignature,
  102. OUT PULONG partitionNumber,
  103. OUT PULONGLONG partitionStart,
  104. OUT PULONGLONG partitionSize,
  105. OUT PBOOLEAN GPTpartition,
  106. OUT PBOOLEAN longSignature
  107. );
  108. NTSTATUS
  109. ExpParseEfiPath (
  110. IN EFI_DEVICE_PATH *pDevicePath,
  111. OUT HARDDRIVE_DEVICE_PATH **ppHardDriveDP,
  112. OUT PWSTR *ppPathName,
  113. OUT PBOOLEAN GPTpartition
  114. );
  115. NTSTATUS
  116. ExpConvertArcName (
  117. IN ULONG OutputType,
  118. OUT PFILE_PATH OutputPath,
  119. IN OUT PULONG OutputPathLength,
  120. IN PWSTR pDeviceName,
  121. IN PWSTR pPathName,
  122. IN ULONG DeviceNameCount
  123. );
  124. NTSTATUS
  125. ExpConvertSignatureName (
  126. IN ULONG OutputType,
  127. OUT PFILE_PATH OutputPath,
  128. IN OUT PULONG OutputPathLength,
  129. IN PWSTR pDeviceName,
  130. IN PWSTR pPathName,
  131. IN ULONG DeviceNameCount
  132. );
  133. NTSTATUS
  134. ExpTranslateHexStringToULONG (
  135. IN PWSTR Name,
  136. OUT PULONG Number
  137. );
  138. NTSTATUS
  139. ExpTranslateHexStringToULONGLONG (
  140. IN PWSTR Name,
  141. OUT PULONGLONG Number
  142. );
  143. NTSTATUS
  144. ExpTranslateHexStringToGUID (
  145. IN PWSTR Name,
  146. OUT GUID *pGuid
  147. );
  148. NTSTATUS
  149. ExpCreateOutputEFI (
  150. OUT PFILE_PATH OutputPath,
  151. IN OUT PULONG OutputPathLength,
  152. IN PDISK_SIGNATURE_NEW pDiskSignature,
  153. IN PULONG pPartitionNumber,
  154. IN PULONGLONG pPartitionStart,
  155. IN PULONGLONG pPartitionSize,
  156. IN PWSTR pPathName,
  157. IN BOOLEAN GPTpartition
  158. );
  159. NTSTATUS
  160. ExpCreateOutputNT (
  161. OUT PFILE_PATH OutputPath,
  162. IN OUT PULONG OutputPathLength,
  163. IN PUNICODE_STRING pDeviceNameString,
  164. IN PWSTR pPathName
  165. );
  166. NTSTATUS
  167. ExpCreateOutputARC (
  168. OUT PFILE_PATH OutputPath,
  169. IN OUT PULONG OutputPathLength,
  170. IN PUNICODE_STRING pDeviceNameString,
  171. IN PWSTR pPathName
  172. );
  173. NTSTATUS
  174. ExpCreateOutputSIGNATURE (
  175. OUT PFILE_PATH OutputPath,
  176. IN OUT PULONG OutputPathLength,
  177. IN PDISK_SIGNATURE_NEW pDiskSignature,
  178. IN PULONG pPartitionNumber,
  179. IN PULONGLONG pPartitionStart,
  180. IN PULONGLONG pPartitionSize,
  181. IN PWSTR pPathName,
  182. IN BOOLEAN GPTpartition
  183. );
  184. NTSTATUS
  185. ExpFindArcName (
  186. IN PUNICODE_STRING pDeviceNameString,
  187. OUT PWSTR *pArcName
  188. );
  189. NTSTATUS
  190. ExpFindDiskSignature (
  191. IN PDISK_SIGNATURE_NEW pSignature,
  192. IN OUT PULONG pPartitionNumber,
  193. OUT PULONG pDiskNumber,
  194. OUT PULONGLONG pPartitionStart,
  195. OUT PULONGLONG pPartitionSize,
  196. IN BOOLEAN GPTpartition
  197. );
  198. NTSTATUS
  199. ExpGetPartitionTableInfo (
  200. IN PWSTR pDeviceName,
  201. OUT PDRIVE_LAYOUT_INFORMATION_EX *ppDriveLayout
  202. );
  203. #endif // defined(EFI_NVRAM_ENABLED)
  204. #if defined(ALLOC_PRAGMA)
  205. #pragma alloc_text(PAGE, NtQuerySystemEnvironmentValue)
  206. #pragma alloc_text(PAGE, NtSetSystemEnvironmentValue)
  207. #pragma alloc_text(PAGE, NtQuerySystemEnvironmentValueEx)
  208. #pragma alloc_text(PAGE, NtSetSystemEnvironmentValueEx)
  209. #pragma alloc_text(PAGE, NtEnumerateSystemEnvironmentValuesEx)
  210. #pragma alloc_text(PAGE, NtAddBootEntry)
  211. #pragma alloc_text(PAGE, NtDeleteBootEntry)
  212. #pragma alloc_text(PAGE, NtModifyBootEntry)
  213. #pragma alloc_text(PAGE, NtEnumerateBootEntries)
  214. #pragma alloc_text(PAGE, NtQueryBootEntryOrder)
  215. #pragma alloc_text(PAGE, NtSetBootEntryOrder)
  216. #pragma alloc_text(PAGE, NtQueryBootOptions)
  217. #pragma alloc_text(PAGE, NtSetBootOptions)
  218. #pragma alloc_text(PAGE, NtTranslateFilePath)
  219. #pragma alloc_text(PAGE, ExpSetBootEntry)
  220. #if defined(EFI_NVRAM_ENABLED)
  221. #pragma alloc_text(PAGE, ExpSafeWcslen)
  222. #pragma alloc_text(PAGE, ExpTranslateArcPath)
  223. #pragma alloc_text(PAGE, ExpTranslateEfiPath)
  224. #pragma alloc_text(PAGE, ExpTranslateNtPath)
  225. #pragma alloc_text(PAGE, ExpTranslateBootEntryNameToId)
  226. #pragma alloc_text(PAGE, ExpTranslateSymbolicLink)
  227. #pragma alloc_text(PAGE, ExpVerifyFilePath)
  228. #pragma alloc_text(PAGE, ExpVerifyWindowsOsOptions)
  229. #pragma alloc_text(PAGE, ExpParseArcPathName)
  230. #pragma alloc_text(PAGE, ExpParseSignatureName)
  231. #pragma alloc_text(PAGE, ExpParseEfiPath)
  232. #pragma alloc_text(PAGE, ExpConvertArcName)
  233. #pragma alloc_text(PAGE, ExpConvertSignatureName)
  234. #pragma alloc_text(PAGE, ExpTranslateHexStringToULONG)
  235. #pragma alloc_text(PAGE, ExpTranslateHexStringToULONGLONG)
  236. #pragma alloc_text(PAGE, ExpTranslateHexStringToGUID)
  237. #pragma alloc_text(PAGE, ExpCreateOutputEFI)
  238. #pragma alloc_text(PAGE, ExpCreateOutputNT)
  239. #pragma alloc_text(PAGE, ExpCreateOutputARC)
  240. #pragma alloc_text(PAGE, ExpCreateOutputSIGNATURE)
  241. #pragma alloc_text(PAGE, ExpFindArcName)
  242. #pragma alloc_text(PAGE, ExpFindDiskSignature)
  243. #pragma alloc_text(PAGE, ExpGetPartitionTableInfo)
  244. #endif // defined(EFI_NVRAM_ENABLED)
  245. #endif // defined(ALLOC_PRAGMA)
  246. //
  247. // Define maximum size of environment value.
  248. //
  249. #define MAXIMUM_ENVIRONMENT_VALUE 1024
  250. //
  251. // Define query/set environment variable synchronization fast mutex.
  252. //
  253. FAST_MUTEX ExpEnvironmentLock;
  254. #if defined(EFI_NVRAM_ENABLED)
  255. //
  256. // Define vendor GUID for EFI boot variables.
  257. //
  258. GUID EfiBootVariablesGuid = EFI_GLOBAL_VARIABLE;
  259. #endif
  260. NTSTATUS
  261. NtQuerySystemEnvironmentValue (
  262. IN PUNICODE_STRING VariableName,
  263. OUT PWSTR VariableValue,
  264. IN USHORT ValueLength,
  265. OUT PUSHORT ReturnLength OPTIONAL
  266. )
  267. /*++
  268. Routine Description:
  269. This function locates the specified system environment variable and
  270. returns its value.
  271. N.B. This service requires the system environment privilege.
  272. Arguments:
  273. Variable - Supplies a pointer to a UNICODE descriptor for the specified
  274. system environment variable.
  275. Value - Supplies a pointer to a buffer that receives the value of the
  276. specified system environment variable.
  277. ValueLength - Supplies the length of the value buffer in bytes.
  278. ReturnLength - Supplies an optional pointer to a variable that receives
  279. the length of the system environment variable value.
  280. Return Value:
  281. STATUS_SUCCESS is returned if the service is successfully executed.
  282. STATUS_PRIVILEGE_NOT_HELD is returned if the caller does not have the
  283. privilege to query a system environment variable.
  284. STATUS_ACCESS_VIOLATION is returned if the output parameter for the
  285. system environment value or the return length cannot be written,
  286. or the descriptor or the name of the system environment variable
  287. cannot be read.
  288. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources exist
  289. for this request to complete.
  290. STATUS_UNSUCCESSFUL - The specified environment variable could not
  291. be located.
  292. --*/
  293. {
  294. ULONG AnsiLength;
  295. ANSI_STRING AnsiString;
  296. ARC_STATUS ArcStatus;
  297. BOOLEAN HasPrivilege;
  298. NTSTATUS NtStatus;
  299. KPROCESSOR_MODE PreviousMode;
  300. UNICODE_STRING UnicodeString;
  301. PCHAR ValueBuffer;
  302. //
  303. // Clear address of ANSI buffer.
  304. //
  305. AnsiString.Buffer = NULL;
  306. //
  307. // Establish an exception handler and attempt to probe and read the
  308. // name of the specified system environment variable, and probe the
  309. // variable value buffer and return length. If the probe or read
  310. // attempt fails, then return the exception code as the service status.
  311. //
  312. try {
  313. //
  314. // Get previous processor mode and probe arguments if necessary.
  315. //
  316. PreviousMode = KeGetPreviousMode();
  317. if (PreviousMode != KernelMode) {
  318. //
  319. // Probe and capture the string descriptor for the system
  320. // environment variable name.
  321. //
  322. ProbeForReadSmallStructure((PVOID)VariableName,
  323. sizeof(UNICODE_STRING),
  324. sizeof(ULONG));
  325. UnicodeString = *VariableName;
  326. //
  327. // Probe the system environment variable name.
  328. //
  329. if (UnicodeString.Length == 0) {
  330. return STATUS_ACCESS_VIOLATION;
  331. }
  332. ProbeForRead((PVOID)UnicodeString.Buffer,
  333. UnicodeString.Length,
  334. sizeof(WCHAR));
  335. //
  336. // Probe the system environment value buffer.
  337. //
  338. ProbeForWrite((PVOID)VariableValue, ValueLength, sizeof(WCHAR));
  339. //
  340. // If argument is present, probe the return length value.
  341. //
  342. if (ARGUMENT_PRESENT(ReturnLength)) {
  343. ProbeForWriteUshort(ReturnLength);
  344. }
  345. //
  346. // Check if the current thread has the privilege to query a system
  347. // environment variable.
  348. //
  349. HasPrivilege = SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege,
  350. PreviousMode);
  351. if (HasPrivilege == FALSE) {
  352. return(STATUS_PRIVILEGE_NOT_HELD);
  353. }
  354. } else {
  355. UnicodeString = *VariableName;
  356. }
  357. //
  358. // Compute the size of the ANSI variable name, allocate a nonpaged
  359. // buffer, and convert the specified UNICODE variable name to ANSI.
  360. //
  361. AnsiLength = RtlUnicodeStringToAnsiSize(&UnicodeString);
  362. AnsiString.Buffer = (PCHAR)ExAllocatePoolWithTag(NonPagedPool, AnsiLength, 'rvnE');
  363. if (AnsiString.Buffer == NULL) {
  364. return STATUS_INSUFFICIENT_RESOURCES;
  365. }
  366. AnsiString.MaximumLength = (USHORT)AnsiLength;
  367. NtStatus = RtlUnicodeStringToAnsiString(&AnsiString,
  368. &UnicodeString,
  369. FALSE);
  370. if (NT_SUCCESS(NtStatus) == FALSE) {
  371. ExFreePool((PVOID)AnsiString.Buffer);
  372. return NtStatus;
  373. }
  374. //
  375. // If an exception occurs during the read of the variable descriptor,
  376. // the read of the variable name, the probe of the variable value, or
  377. // the probe of the return length, then always handle the exception,
  378. // free the ANSI string buffer if necessary, and return the exception
  379. // code as the status value.
  380. //
  381. } except (EXCEPTION_EXECUTE_HANDLER) {
  382. if (AnsiString.Buffer != NULL) {
  383. ExFreePool((PVOID)AnsiString.Buffer);
  384. }
  385. return GetExceptionCode();
  386. }
  387. //
  388. // Allocate nonpaged pool to receive variable value.
  389. //
  390. ValueBuffer = (PCHAR)ExAllocatePoolWithTag(NonPagedPool, MAXIMUM_ENVIRONMENT_VALUE, 'rvnE');
  391. if (ValueBuffer == NULL) {
  392. ExFreePool((PVOID)AnsiString.Buffer);
  393. return STATUS_INSUFFICIENT_RESOURCES;
  394. }
  395. //
  396. // Get the system environment variable value.
  397. //
  398. KeEnterCriticalRegion();
  399. ExAcquireFastMutexUnsafe(&ExpEnvironmentLock);
  400. ArcStatus = HalGetEnvironmentVariable(AnsiString.Buffer,
  401. MAXIMUM_ENVIRONMENT_VALUE,
  402. ValueBuffer);
  403. ExReleaseFastMutexUnsafe(&ExpEnvironmentLock);
  404. KeLeaveCriticalRegion();
  405. //
  406. // Free the ANSI string buffer used to hold the variable name.
  407. //
  408. ExFreePool((PVOID)AnsiString.Buffer);
  409. //
  410. // If the specified environment variable was not found, then free
  411. // the value buffer and return an unsuccessful status.
  412. //
  413. if (ArcStatus != ESUCCESS) {
  414. ExFreePool((PVOID)ValueBuffer);
  415. return STATUS_UNSUCCESSFUL;
  416. }
  417. //
  418. // Establish an exception handler and attempt to write the value of the
  419. // specified system environment variable. If the write attempt fails,
  420. // then return the exception code as the service status.
  421. //
  422. try {
  423. //
  424. // Initialize an ANSI string descriptor, set the maximum length and
  425. // buffer address for a UNICODE string descriptor, and convert the
  426. // ANSI variable value to UNICODE.
  427. //
  428. RtlInitString(&AnsiString, ValueBuffer);
  429. UnicodeString.Buffer = (PWSTR)VariableValue;
  430. UnicodeString.MaximumLength = ValueLength;
  431. NtStatus = RtlAnsiStringToUnicodeString(&UnicodeString,
  432. &AnsiString,
  433. FALSE);
  434. //
  435. // If argument is present, then write the length of the UNICODE
  436. // variable value.
  437. //
  438. if (ARGUMENT_PRESENT(ReturnLength)) {
  439. *ReturnLength = UnicodeString.Length;
  440. }
  441. //
  442. // Free the value buffer used to hold the variable value.
  443. //
  444. ExFreePool((PVOID)ValueBuffer);
  445. return NtStatus;
  446. //
  447. // If an exception occurs during the write of the variable value, or
  448. // the write of the return length, then always handle the exception
  449. // and return the exception code as the status value.
  450. //
  451. } except (EXCEPTION_EXECUTE_HANDLER) {
  452. ExFreePool((PVOID)ValueBuffer);
  453. return GetExceptionCode();
  454. }
  455. }
  456. NTSTATUS
  457. NtSetSystemEnvironmentValue (
  458. IN PUNICODE_STRING VariableName,
  459. IN PUNICODE_STRING VariableValue
  460. )
  461. /*++
  462. Routine Description:
  463. This function sets the specified system environment variable to the
  464. specified value.
  465. N.B. This service requires the system environment privilege.
  466. Arguments:
  467. Variable - Supplies a pointer to a UNICODE descriptor for the specified
  468. system environment variable name.
  469. Value - Supplies a pointer to a UNICODE descriptor for the specified
  470. system environment variable value.
  471. Return Value:
  472. STATUS_SUCCESS is returned if the service is successfully executed.
  473. STATUS_PRIVILEGE_NOT_HELD is returned if the caller does not have the
  474. privilege to set a system environment variable.
  475. STATUS_ACCESS_VIOLATION is returned if the input parameter for the
  476. system environment variable or value cannot be read.
  477. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources exist
  478. for this request to complete.
  479. --*/
  480. {
  481. ULONG AnsiLength1;
  482. ULONG AnsiLength2;
  483. ANSI_STRING AnsiString1;
  484. ANSI_STRING AnsiString2;
  485. ARC_STATUS ArcStatus;
  486. BOOLEAN HasPrivilege;
  487. KPROCESSOR_MODE PreviousMode;
  488. NTSTATUS NtStatus;
  489. UNICODE_STRING UnicodeString1;
  490. UNICODE_STRING UnicodeString2;
  491. //
  492. // Clear address of ANSI buffers.
  493. //
  494. AnsiString1.Buffer = NULL;
  495. AnsiString2.Buffer = NULL;
  496. //
  497. // Establish an exception handler and attempt to set the value of the
  498. // specified system environment variable. If the read attempt for the
  499. // system environment variable or value fails, then return the exception
  500. // code as the service status. Otherwise, return either success or access
  501. // denied as the service status.
  502. //
  503. try {
  504. //
  505. // Get previous processor mode and probe arguments if necessary.
  506. //
  507. PreviousMode = KeGetPreviousMode();
  508. if (PreviousMode != KernelMode) {
  509. //
  510. // Probe and capture the string descriptor for the system
  511. // environment variable name.
  512. //
  513. ProbeForReadSmallStructure((PVOID)VariableName,
  514. sizeof(UNICODE_STRING),
  515. sizeof(ULONG));
  516. UnicodeString1 = *VariableName;
  517. //
  518. // Handle a zero length string explicitly since probing does not,
  519. // the error code is unusual, but it's what we would have done with
  520. // the HAL return code too.
  521. //
  522. if (UnicodeString1.Length == 0) {
  523. return STATUS_INSUFFICIENT_RESOURCES;
  524. }
  525. //
  526. // Probe the system environment variable name.
  527. //
  528. ProbeForRead((PVOID)UnicodeString1.Buffer,
  529. UnicodeString1.Length,
  530. sizeof(WCHAR));
  531. //
  532. // Probe and capture the string descriptor for the system
  533. // environment variable value.
  534. //
  535. ProbeForReadSmallStructure((PVOID)VariableValue,
  536. sizeof(UNICODE_STRING),
  537. sizeof(ULONG));
  538. UnicodeString2 = *VariableValue;
  539. //
  540. // Handle a zero length string explicitly since probing does not
  541. // the error code is unusual, but it's what we would have done with
  542. // the HAL return code too.
  543. //
  544. if (UnicodeString2.Length == 0) {
  545. return STATUS_INSUFFICIENT_RESOURCES;
  546. }
  547. //
  548. // Probe the system environment variable value.
  549. //
  550. ProbeForRead((PVOID)UnicodeString2.Buffer,
  551. UnicodeString2.Length,
  552. sizeof(WCHAR));
  553. //
  554. // Check if the current thread has the privilege to query a system
  555. // environment variable.
  556. //
  557. HasPrivilege = SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege,
  558. PreviousMode);
  559. if (HasPrivilege == FALSE) {
  560. return(STATUS_PRIVILEGE_NOT_HELD);
  561. }
  562. } else {
  563. UnicodeString1 = *VariableName;
  564. UnicodeString2 = *VariableValue;
  565. }
  566. //
  567. // Compute the size of the ANSI variable name, allocate a nonpaged
  568. // buffer, and convert the specified UNICODE variable name to ANSI.
  569. //
  570. AnsiLength1 = RtlUnicodeStringToAnsiSize(&UnicodeString1);
  571. AnsiString1.Buffer = (PCHAR)ExAllocatePoolWithTag(NonPagedPool, AnsiLength1, 'rvnE');
  572. if (AnsiString1.Buffer == NULL) {
  573. return STATUS_INSUFFICIENT_RESOURCES;
  574. }
  575. AnsiString1.MaximumLength = (USHORT)AnsiLength1;
  576. NtStatus = RtlUnicodeStringToAnsiString(&AnsiString1,
  577. &UnicodeString1,
  578. FALSE);
  579. if (NT_SUCCESS(NtStatus) == FALSE) {
  580. ExFreePool((PVOID)AnsiString1.Buffer);
  581. return NtStatus;
  582. }
  583. //
  584. // Compute the size of the ANSI variable value, allocate a nonpaged
  585. // buffer, and convert the specified UNICODE variable value to ANSI.
  586. //
  587. AnsiLength2 = RtlUnicodeStringToAnsiSize(&UnicodeString2);
  588. AnsiString2.Buffer = (PCHAR)ExAllocatePoolWithTag(NonPagedPool, AnsiLength2, 'rvnE');
  589. if (AnsiString2.Buffer == NULL) {
  590. ExFreePool((PVOID)AnsiString1.Buffer);
  591. return STATUS_INSUFFICIENT_RESOURCES;
  592. }
  593. AnsiString2.MaximumLength = (USHORT)AnsiLength2;
  594. NtStatus = RtlUnicodeStringToAnsiString(&AnsiString2,
  595. &UnicodeString2,
  596. FALSE);
  597. if (NT_SUCCESS(NtStatus) == FALSE) {
  598. ExFreePool((PVOID)AnsiString1.Buffer);
  599. ExFreePool((PVOID)AnsiString2.Buffer);
  600. return NtStatus;
  601. }
  602. //
  603. // If an exception occurs during the read of the variable descriptor,
  604. // the read of the variable name, the read of the value descriptor, or
  605. // the read of the value, then always handle the exception, free the
  606. // ANSI string buffers if necessary, and return the exception code as
  607. // the status value.
  608. //
  609. } except (EXCEPTION_EXECUTE_HANDLER) {
  610. if (AnsiString1.Buffer != NULL) {
  611. ExFreePool((PVOID)AnsiString1.Buffer);
  612. }
  613. if (AnsiString2.Buffer != NULL) {
  614. ExFreePool((PVOID)AnsiString2.Buffer);
  615. }
  616. return GetExceptionCode();
  617. }
  618. //
  619. // Set the system environment variable value.
  620. //
  621. KeEnterCriticalRegion();
  622. ExAcquireFastMutexUnsafe(&ExpEnvironmentLock);
  623. ArcStatus = HalSetEnvironmentVariable(AnsiString1.Buffer,
  624. AnsiString2.Buffer);
  625. ExReleaseFastMutexUnsafe(&ExpEnvironmentLock);
  626. KeLeaveCriticalRegion();
  627. //
  628. // Free the ANSI string buffers used to hold the variable name and value.
  629. //
  630. ExFreePool((PVOID)AnsiString1.Buffer);
  631. ExFreePool((PVOID)AnsiString2.Buffer);
  632. //
  633. // If the specified value of the specified environment variable was
  634. // successfully set, then return a success status. Otherwise, return
  635. // insufficient resources.
  636. //
  637. if (ArcStatus == ESUCCESS) {
  638. return STATUS_SUCCESS;
  639. } else {
  640. return STATUS_INSUFFICIENT_RESOURCES;
  641. }
  642. }
  643. NTSTATUS
  644. NtQuerySystemEnvironmentValueEx (
  645. IN PUNICODE_STRING VariableName,
  646. IN LPGUID VendorGuid,
  647. OUT PVOID Value,
  648. IN OUT PULONG ValueLength,
  649. OUT PULONG Attributes OPTIONAL
  650. )
  651. /*++
  652. Routine Description:
  653. This function locates the specified system environment variable and
  654. return its value.
  655. N.B. This service requires the system environment privilege.
  656. Arguments:
  657. VariableName - Supplies a pointer to a UNICODE descriptor for the specified
  658. system environment variable.
  659. VendorGuid - Supplies the GUID for the vendor associated with the variable.
  660. Variables are grouped into namespaces based on their vendor GUIDs. Some
  661. platforms may not support vendor GUIDs. On these platforms, all
  662. variables are in a single namespace, and this routine ignores VendorGuid.
  663. Value - Supplies a pointer to a buffer that receives the value of the
  664. specified system environment variable.
  665. ValueLength - On input, supplies the length in bytes of the Value buffer.
  666. On output, returns the length in bytes of the variable value. If the
  667. input buffer is large enough, then ValueLength indicates the amount
  668. of data copied into Value. If the input buffer is too small, then
  669. nothing is copied into the buffer, and ValueLength indicates the
  670. required buffer length.
  671. Attributes - Supplies an optional pointer to a ULONG to receive the
  672. attributes of the variable.
  673. Return Value:
  674. STATUS_SUCCESS The function succeeded.
  675. STATUS_INSUFFICIENT_RESOURCES Insufficient system resources exist
  676. for this request to complete.
  677. STATUS_BUFFER_TOO_SMALL The input buffer was too small.
  678. STATUS_VARIABLE_NOT_FOUND The requested variable does not exist.
  679. STATUS_INVALID_PARAMETER One of the parameters is invalid.
  680. STATUS_NOT_IMPLEMENTED This function is not supported on this platform.
  681. STATUS_UNSUCCESSFUL The firmware returned an unrecognized error.
  682. STATUS_PRIVILEGE_NOT_HELD The caller does not have the required privilege.
  683. STATUS_ACCESS_VIOLATION One of the input parameters cannot be read,
  684. or one of the output parameters cannot be written.
  685. --*/
  686. {
  687. #if !defined(EFI_NVRAM_ENABLED)
  688. UNREFERENCED_PARAMETER(VariableName);
  689. UNREFERENCED_PARAMETER(VendorGuid);
  690. UNREFERENCED_PARAMETER(Value);
  691. UNREFERENCED_PARAMETER(ValueLength);
  692. UNREFERENCED_PARAMETER(Attributes);
  693. return STATUS_NOT_IMPLEMENTED;
  694. #else
  695. BOOLEAN HasPrivilege;
  696. NTSTATUS NtStatus;
  697. KPROCESSOR_MODE PreviousMode;
  698. UNICODE_STRING UnicodeString;
  699. PWSTR LocalUnicodeBuffer = NULL;
  700. GUID LocalGuid;
  701. PCHAR LockedValueBuffer;
  702. ULONG LocalValueLength;
  703. ULONG LocalAttributes;
  704. PVOID LockVariable;
  705. //
  706. // Establish an exception handler and attempt to probe and read the name
  707. // of the specified system environment variable, probe the variable value
  708. // buffer, probe and read the length argument, and probe the attributes
  709. // argument. If the probe attempt fails, then return the exception code
  710. // as the service status.
  711. //
  712. try {
  713. //
  714. // Get previous processor mode and probe arguments if necessary.
  715. //
  716. PreviousMode = KeGetPreviousMode();
  717. if (PreviousMode != KernelMode) {
  718. //
  719. // Probe and capture the string descriptor for the system
  720. // environment variable name.
  721. //
  722. ProbeForReadSmallStructure((PVOID)VariableName,
  723. sizeof(UNICODE_STRING),
  724. sizeof(ULONG));
  725. UnicodeString = *VariableName;
  726. //
  727. // Probe the system environment variable name.
  728. //
  729. if (UnicodeString.Length == 0) {
  730. return STATUS_ACCESS_VIOLATION;
  731. }
  732. ProbeForRead((PVOID)UnicodeString.Buffer,
  733. UnicodeString.Length,
  734. sizeof(WCHAR));
  735. //
  736. // Probe the vendor GUID.
  737. //
  738. ProbeForReadSmallStructure((PVOID)VendorGuid, sizeof(GUID), sizeof(ULONG));
  739. //
  740. // Probe and capture the length value.
  741. //
  742. ProbeForWriteUlong(ValueLength);
  743. LocalValueLength = *ValueLength;
  744. //
  745. // Probe the system environment value buffer.
  746. //
  747. if (!ARGUMENT_PRESENT(Value)) {
  748. LocalValueLength = 0;
  749. }
  750. if (LocalValueLength != 0) {
  751. ProbeForWrite((PVOID)Value, LocalValueLength, sizeof(UCHAR));
  752. }
  753. //
  754. // If argument is present, probe the attributes parameter.
  755. //
  756. if (ARGUMENT_PRESENT(Attributes)) {
  757. ProbeForWriteUlong(Attributes);
  758. }
  759. //
  760. // Check if the current thread has the privilege to query a system
  761. // environment variable.
  762. //
  763. HasPrivilege = SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege,
  764. PreviousMode);
  765. if (HasPrivilege == FALSE) {
  766. return STATUS_PRIVILEGE_NOT_HELD;
  767. }
  768. } else {
  769. UnicodeString = *VariableName;
  770. LocalValueLength = *ValueLength;
  771. if (!ARGUMENT_PRESENT(Value)) {
  772. LocalValueLength = 0;
  773. }
  774. }
  775. //
  776. // Capture the vendor GUID.
  777. //
  778. RtlCopyMemory( &LocalGuid, VendorGuid, sizeof(GUID) );
  779. //
  780. // Allocate a nonpaged buffer and copy the specified Unicode variable
  781. // name into that buffer. We do this for two reasons: 1) we need the
  782. // string to be in nonpaged pool; and 2) the string needs to be null-
  783. // terminated, and it might not be already.
  784. //
  785. LocalUnicodeBuffer = (PWSTR)ExAllocatePoolWithTag(NonPagedPool,
  786. UnicodeString.Length + sizeof(WCHAR),
  787. 'rvnE');
  788. if (LocalUnicodeBuffer == NULL) {
  789. return STATUS_INSUFFICIENT_RESOURCES;
  790. }
  791. RtlCopyMemory(LocalUnicodeBuffer, UnicodeString.Buffer, UnicodeString.Length);
  792. LocalUnicodeBuffer[UnicodeString.Length/sizeof(WCHAR)] = 0;
  793. //
  794. // If an exception occurs during the read of the variable descriptor,
  795. // the read of the variable name, the read of the vendor GUID, the probe
  796. // of the variable value, the read of the input length, or the probe
  797. // of the attributes parameter, then always handle the exception,
  798. // free the Unicode string buffer if necessary, and return the exception
  799. // code as the status value.
  800. //
  801. } except (EXCEPTION_EXECUTE_HANDLER) {
  802. if (LocalUnicodeBuffer != NULL) {
  803. ExFreePool((PVOID)LocalUnicodeBuffer);
  804. }
  805. return GetExceptionCode();
  806. }
  807. //
  808. // Lock the caller's value buffer in memory.
  809. //
  810. if (LocalValueLength != 0) {
  811. NtStatus = ExLockUserBuffer(Value,
  812. LocalValueLength,
  813. &LockedValueBuffer,
  814. &LockVariable);
  815. if (!NT_SUCCESS(NtStatus)) {
  816. ExFreePool((PVOID)LocalUnicodeBuffer);
  817. return NtStatus;
  818. }
  819. } else {
  820. LockedValueBuffer = NULL;
  821. LockVariable = NULL;
  822. }
  823. //
  824. // Get the system environment variable value.
  825. //
  826. KeEnterCriticalRegion();
  827. ExAcquireFastMutexUnsafe(&ExpEnvironmentLock);
  828. NtStatus = HalGetEnvironmentVariableEx(LocalUnicodeBuffer,
  829. &LocalGuid,
  830. LockedValueBuffer,
  831. &LocalValueLength,
  832. &LocalAttributes);
  833. ExReleaseFastMutexUnsafe(&ExpEnvironmentLock);
  834. KeLeaveCriticalRegion();
  835. //
  836. // Free the Unicode string buffer used to hold the variable name.
  837. //
  838. ExFreePool((PVOID)LocalUnicodeBuffer);
  839. //
  840. // Unlock the value buffer.
  841. //
  842. if (LockVariable != NULL) {
  843. ExUnlockUserBuffer(LockVariable);
  844. }
  845. //
  846. // Establish an exception handler and attempt to write the return
  847. // length and the attributes. If either of the write attempts fail,
  848. // then return the exception code as the service status.
  849. //
  850. try {
  851. //
  852. // Write the length of the variable value.
  853. //
  854. *ValueLength = LocalValueLength;
  855. //
  856. // If argument is present, then write the variable attributes.
  857. //
  858. if (ARGUMENT_PRESENT(Attributes)) {
  859. *Attributes = LocalAttributes;
  860. }
  861. return NtStatus;
  862. //
  863. // If an exception occurs during the write of the return length or
  864. // the write of the attributes, then always handle the exception
  865. // and return the exception code as the status value.
  866. //
  867. } except (EXCEPTION_EXECUTE_HANDLER) {
  868. return GetExceptionCode();
  869. }
  870. #endif // else !defined(EFI_NVRAM_ENABLED)
  871. } // NtQuerySystemEnvironmentValueEx
  872. NTSTATUS
  873. NtSetSystemEnvironmentValueEx (
  874. IN PUNICODE_STRING VariableName,
  875. IN LPGUID VendorGuid,
  876. IN PVOID Value,
  877. IN ULONG ValueLength,
  878. IN ULONG Attributes
  879. )
  880. /*++
  881. Routine Description:
  882. This function sets the specified system environment variable to the
  883. specified value.
  884. N.B. This service requires the system environment privilege.
  885. Arguments:
  886. VariableName - Supplies a pointer to a UNICODE descriptor for the specified
  887. system environment variable.
  888. VendorGuid - Supplies the GUID for the vendor associated with the variable.
  889. Variables are grouped into namespaces based on their vendor GUIDs. Some
  890. platforms may not support vendor GUIDs. On these platforms, all
  891. variables are in a single namespace, and this routine ignores VendorGuid.
  892. Value - Supplies a pointer to a buffer that contains the new variable value.
  893. ValueLength - Supplies the length in bytes of the Value buffer.
  894. Attributes - Supplies the attributes of the variable. The attribute bit
  895. VARIABLE_ATTRIBUTE_NON_VOLATILE MUST be set.
  896. Return Value:
  897. STATUS_SUCCESS The function succeeded.
  898. STATUS_INSUFFICIENT_RESOURCES Insufficient system resources exist
  899. for this request to complete.
  900. STATUS_INVALID_PARAMETER One of the parameters is invalid.
  901. STATUS_NOT_IMPLEMENTED This function is not supported on this platform.
  902. STATUS_UNSUCCESSFUL The firmware returned an unrecognized error.
  903. STATUS_PRIVILEGE_NOT_HELD The caller does not have the required privilege.
  904. STATUS_ACCESS_VIOLATION One of the input parameters cannot be read.
  905. --*/
  906. {
  907. #if !defined(EFI_NVRAM_ENABLED)
  908. UNREFERENCED_PARAMETER(VariableName);
  909. UNREFERENCED_PARAMETER(VendorGuid);
  910. UNREFERENCED_PARAMETER(Value);
  911. UNREFERENCED_PARAMETER(ValueLength);
  912. UNREFERENCED_PARAMETER(Attributes);
  913. return STATUS_NOT_IMPLEMENTED;
  914. #else
  915. BOOLEAN HasPrivilege;
  916. NTSTATUS NtStatus;
  917. KPROCESSOR_MODE PreviousMode;
  918. UNICODE_STRING UnicodeString;
  919. PWSTR LocalUnicodeBuffer = NULL;
  920. GUID LocalGuid;
  921. PCHAR LockedValueBuffer;
  922. PVOID LockVariable;
  923. //
  924. // Establish an exception handler and attempt to probe and read the
  925. // name of the specified system environment variable, probe and read
  926. // the vendor GUID, and probe the variable value buffer. If the probe
  927. // attempt fails, then return the exception code as the service status.
  928. //
  929. try {
  930. //
  931. // Get previous processor mode and probe arguments if necessary.
  932. //
  933. PreviousMode = KeGetPreviousMode();
  934. if (PreviousMode != KernelMode) {
  935. //
  936. // Probe and capture the string descriptor for the system
  937. // environment variable name.
  938. //
  939. ProbeForReadSmallStructure((PVOID)VariableName,
  940. sizeof(UNICODE_STRING),
  941. sizeof(ULONG));
  942. UnicodeString = *VariableName;
  943. //
  944. // Probe the system environment variable name.
  945. //
  946. if (UnicodeString.Length == 0) {
  947. return STATUS_ACCESS_VIOLATION;
  948. }
  949. ProbeForRead((PVOID)UnicodeString.Buffer,
  950. UnicodeString.Length,
  951. sizeof(WCHAR));
  952. //
  953. // Probe the vendor GUID.
  954. //
  955. ProbeForReadSmallStructure((PVOID)VendorGuid, sizeof(GUID), sizeof(ULONG));
  956. //
  957. // Probe the system environment value buffer.
  958. //
  959. if (!ARGUMENT_PRESENT(Value)) {
  960. ValueLength = 0;
  961. }
  962. if (ValueLength != 0) {
  963. ProbeForWrite((PVOID)Value, ValueLength, sizeof(UCHAR));
  964. }
  965. //
  966. // Check if the current thread has the privilege to set a system
  967. // environment variable.
  968. //
  969. HasPrivilege = SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege,
  970. PreviousMode);
  971. if (HasPrivilege == FALSE) {
  972. return STATUS_PRIVILEGE_NOT_HELD;
  973. }
  974. } else {
  975. UnicodeString = *VariableName;
  976. if (!ARGUMENT_PRESENT(Value)) {
  977. ValueLength = 0;
  978. }
  979. }
  980. //
  981. // Capture the vendor GUID.
  982. //
  983. RtlCopyMemory( &LocalGuid, VendorGuid, sizeof(GUID) );
  984. //
  985. // Allocate a nonpaged buffer and copy the specified Unicode variable
  986. // name into that buffer. We do this for two reasons: 1) we need the
  987. // string to be in nonpaged pool; and 2) the string needs to be null-
  988. // terminated, and it might not be already.
  989. //
  990. LocalUnicodeBuffer = (PWSTR)ExAllocatePoolWithTag(NonPagedPool,
  991. UnicodeString.Length + sizeof(WCHAR),
  992. 'rvnE');
  993. if (LocalUnicodeBuffer == NULL) {
  994. return STATUS_INSUFFICIENT_RESOURCES;
  995. }
  996. RtlCopyMemory(LocalUnicodeBuffer, UnicodeString.Buffer, UnicodeString.Length);
  997. LocalUnicodeBuffer[UnicodeString.Length/sizeof(WCHAR)] = 0;
  998. //
  999. // If an exception occurs during the read of the variable descriptor,
  1000. // the read of the variable name, the read of the vendor GUID or the probe
  1001. // of the variable value, then always handle the exception, free the Unicode
  1002. // string buffer if necessary, and return the exception code as the status
  1003. // value.
  1004. //
  1005. } except (EXCEPTION_EXECUTE_HANDLER) {
  1006. if (LocalUnicodeBuffer != NULL) {
  1007. ExFreePool((PVOID)LocalUnicodeBuffer);
  1008. }
  1009. return GetExceptionCode();
  1010. }
  1011. //
  1012. // Lock the caller's value buffer in memory.
  1013. //
  1014. if (ValueLength != 0) {
  1015. NtStatus = ExLockUserBuffer(Value,
  1016. ValueLength,
  1017. &LockedValueBuffer,
  1018. &LockVariable);
  1019. if (!NT_SUCCESS(NtStatus)) {
  1020. ExFreePool((PVOID)LocalUnicodeBuffer);
  1021. return NtStatus;
  1022. }
  1023. } else {
  1024. LockedValueBuffer = NULL;
  1025. LockVariable = NULL;
  1026. }
  1027. //
  1028. // Set the system environment variable value.
  1029. //
  1030. KeEnterCriticalRegion();
  1031. ExAcquireFastMutexUnsafe(&ExpEnvironmentLock);
  1032. NtStatus = HalSetEnvironmentVariableEx(LocalUnicodeBuffer,
  1033. &LocalGuid,
  1034. LockedValueBuffer,
  1035. ValueLength,
  1036. Attributes);
  1037. ExReleaseFastMutexUnsafe(&ExpEnvironmentLock);
  1038. KeLeaveCriticalRegion();
  1039. //
  1040. // Free the Unicode string buffer used to hold the variable name.
  1041. //
  1042. ExFreePool((PVOID)LocalUnicodeBuffer);
  1043. //
  1044. // Unlock the value buffer.
  1045. //
  1046. if (LockVariable != NULL) {
  1047. ExUnlockUserBuffer(LockVariable);
  1048. }
  1049. return NtStatus;
  1050. #endif // else !defined(EFI_NVRAM_ENABLED)
  1051. } // NtSetSystemEnvironmentValueEx
  1052. NTSTATUS
  1053. NtEnumerateSystemEnvironmentValuesEx (
  1054. IN ULONG InformationClass,
  1055. OUT PVOID Buffer,
  1056. IN OUT PULONG BufferLength
  1057. )
  1058. /*++
  1059. Routine Description:
  1060. This function returns information about system environment variables.
  1061. N.B. This service requires the system environment privilege.
  1062. Arguments:
  1063. InformationClass - Specifies the type of information to return.
  1064. Buffer - Supplies the address of the buffer that is to receive the
  1065. returned data. The format of the returned data depends on
  1066. InformationClass.
  1067. BufferLength - On input, supplies the length in bytes of the buffer.
  1068. On output, returns the length in bytes of the returned data.
  1069. If the input buffer is large enough, then BufferLength indicates
  1070. the amount of data copied into Buffer. If the input buffer is too
  1071. small, then BufferLength indicates the required buffer length.
  1072. Return Value:
  1073. STATUS_SUCCESS The function succeeded.
  1074. STATUS_BUFFER_TOO_SMALL The input buffer was too small.
  1075. STATUS_INVALID_PARAMETER One of the parameters is invalid.
  1076. STATUS_NOT_IMPLEMENTED This function is not supported on this platform.
  1077. STATUS_UNSUCCESSFUL The firmware returned an unrecognized error.
  1078. STATUS_PRIVILEGE_NOT_HELD The caller does not have the required privilege.
  1079. STATUS_ACCESS_VIOLATION One of the input parameters cannot be read,
  1080. or one of the output parameters cannot be written.
  1081. --*/
  1082. {
  1083. #if !defined(EFI_NVRAM_ENABLED)
  1084. UNREFERENCED_PARAMETER(InformationClass);
  1085. UNREFERENCED_PARAMETER(Buffer);
  1086. UNREFERENCED_PARAMETER(BufferLength);
  1087. return STATUS_NOT_IMPLEMENTED;
  1088. #else
  1089. BOOLEAN HasPrivilege;
  1090. NTSTATUS NtStatus;
  1091. KPROCESSOR_MODE PreviousMode;
  1092. PCHAR LockedBuffer;
  1093. ULONG LocalBufferLength;
  1094. PVOID LockVariable;
  1095. //
  1096. // Establish an exception handler and attempt to probe the return buffer
  1097. // and probe and read the buffer length. If the probe attempt fails, then
  1098. // return the exception code as the service status.
  1099. //
  1100. try {
  1101. //
  1102. // Get previous processor mode and probe arguments if necessary.
  1103. //
  1104. PreviousMode = KeGetPreviousMode();
  1105. if (PreviousMode != KernelMode) {
  1106. //
  1107. // Probe and capture the input buffer length.
  1108. //
  1109. ProbeForWriteUlong(BufferLength);
  1110. LocalBufferLength = *BufferLength;
  1111. //
  1112. // Probe the return buffer.
  1113. //
  1114. if (!ARGUMENT_PRESENT(Buffer)) {
  1115. LocalBufferLength = 0;
  1116. }
  1117. if (LocalBufferLength != 0) {
  1118. ProbeForWrite((PVOID)Buffer, LocalBufferLength, sizeof(ULONG));
  1119. }
  1120. //
  1121. // Check if the current thread has the privilege to enumerate
  1122. // system environment variables.
  1123. //
  1124. HasPrivilege = SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege,
  1125. PreviousMode);
  1126. if (HasPrivilege == FALSE) {
  1127. return STATUS_PRIVILEGE_NOT_HELD;
  1128. }
  1129. } else {
  1130. LocalBufferLength = *BufferLength;
  1131. if (!ARGUMENT_PRESENT(Buffer)) {
  1132. LocalBufferLength = 0;
  1133. }
  1134. }
  1135. //
  1136. // If an exception occurs during the probe of the return buffer or the
  1137. // read of the input length, then always handle the exception and return
  1138. // the exception code as the status value.
  1139. //
  1140. } except (EXCEPTION_EXECUTE_HANDLER) {
  1141. return GetExceptionCode();
  1142. }
  1143. //
  1144. // Lock the caller's return buffer in memory.
  1145. //
  1146. if (LocalBufferLength != 0) {
  1147. NtStatus = ExLockUserBuffer(Buffer,
  1148. LocalBufferLength,
  1149. &LockedBuffer,
  1150. &LockVariable);
  1151. if (!NT_SUCCESS(NtStatus)) {
  1152. return NtStatus;
  1153. }
  1154. } else {
  1155. LockedBuffer = NULL;
  1156. LockVariable = NULL;
  1157. }
  1158. //
  1159. // Enumerate the system environment variables.
  1160. //
  1161. KeEnterCriticalRegion();
  1162. ExAcquireFastMutexUnsafe(&ExpEnvironmentLock);
  1163. NtStatus = HalEnumerateEnvironmentVariablesEx(InformationClass,
  1164. LockedBuffer,
  1165. &LocalBufferLength);
  1166. ExReleaseFastMutexUnsafe(&ExpEnvironmentLock);
  1167. KeLeaveCriticalRegion();
  1168. //
  1169. // Unlock the return buffer.
  1170. //
  1171. if (LockVariable != NULL) {
  1172. ExUnlockUserBuffer(LockVariable);
  1173. }
  1174. //
  1175. // Establish an exception handler and attempt to write the return length.
  1176. // If the write attempt fails, then return the exception code as the
  1177. // service status.
  1178. //
  1179. try {
  1180. //
  1181. // Write the length of the returned data.
  1182. //
  1183. *BufferLength = LocalBufferLength;
  1184. return NtStatus;
  1185. //
  1186. // If an exception occurs during the write of the return length, then
  1187. // always handle the exception and return the exception code as the
  1188. // status value.
  1189. //
  1190. } except (EXCEPTION_EXECUTE_HANDLER) {
  1191. return GetExceptionCode();
  1192. }
  1193. #endif // else !defined(EFI_NVRAM_ENABLED)
  1194. } // NtEnumerateSystemEnvironmentValuesEx
  1195. NTSTATUS
  1196. NtAddBootEntry (
  1197. IN PBOOT_ENTRY BootEntry,
  1198. OUT PULONG Id OPTIONAL
  1199. )
  1200. /*++
  1201. Routine Description:
  1202. This function adds a boot entry to the system environment.
  1203. N.B. This service requires the system environment privilege.
  1204. Arguments:
  1205. BootEntry - Supplies the address of a BOOT_ENTRY that describes the
  1206. new boot entry.
  1207. Id - Supplies the address of a ULONG that is to receive the identifier
  1208. assigned to the new boot entry.
  1209. Return Value:
  1210. STATUS_SUCCESS The function succeeded.
  1211. STATUS_INVALID_PARAMETER One of the parameters is invalid.
  1212. STATUS_NOT_IMPLEMENTED This function is not supported on this platform.
  1213. STATUS_UNSUCCESSFUL The firmware returned an unrecognized error.
  1214. STATUS_PRIVILEGE_NOT_HELD The caller does not have the required privilege.
  1215. STATUS_ACCESS_VIOLATION One of the input parameters cannot be read,
  1216. or one of the output parameters cannot be written.
  1217. --*/
  1218. {
  1219. return ExpSetBootEntry(TRUE, BootEntry, Id);
  1220. } // NtAddBootEntry
  1221. NTSTATUS
  1222. NtDeleteBootEntry (
  1223. IN ULONG Id
  1224. )
  1225. /*++
  1226. Routine Description:
  1227. This function deletes an existing boot entry from the system environment.
  1228. N.B. This service requires the system environment privilege.
  1229. Arguments:
  1230. Id - Supplies the identifier of the boot entry that is to be deleted.
  1231. Return Value:
  1232. STATUS_SUCCESS The function succeeded.
  1233. STATUS_INVALID_PARAMETER One of the parameters is invalid.
  1234. STATUS_NOT_IMPLEMENTED This function is not supported on this platform.
  1235. STATUS_VARIABLE_NOT_FOUND The Id specifies a boot entry that does not exist.
  1236. STATUS_UNSUCCESSFUL The firmware returned an unrecognized error.
  1237. STATUS_PRIVILEGE_NOT_HELD The caller does not have the required privilege.
  1238. STATUS_ACCESS_VIOLATION One of the input parameters cannot be read,
  1239. or one of the output parameters cannot be written.
  1240. --*/
  1241. {
  1242. #if !defined(EFI_NVRAM_ENABLED)
  1243. UNREFERENCED_PARAMETER(Id);
  1244. return STATUS_NOT_IMPLEMENTED;
  1245. #else
  1246. BOOLEAN HasPrivilege;
  1247. NTSTATUS NtStatus;
  1248. KPROCESSOR_MODE PreviousMode;
  1249. WCHAR idString[9];
  1250. ULONG length;
  1251. //
  1252. // Verify that the input identifier is in range.
  1253. //
  1254. if (Id > MAXUSHORT) {
  1255. return STATUS_INVALID_PARAMETER;
  1256. }
  1257. PreviousMode = KeGetPreviousMode();
  1258. if (PreviousMode != KernelMode) {
  1259. //
  1260. // Check if the current thread has the privilege to query the
  1261. // system boot order list.
  1262. //
  1263. HasPrivilege = SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege,
  1264. PreviousMode);
  1265. if (HasPrivilege == FALSE) {
  1266. return STATUS_PRIVILEGE_NOT_HELD;
  1267. }
  1268. }
  1269. //
  1270. // Verify that the provided identifier exists.
  1271. //
  1272. KeEnterCriticalRegion();
  1273. ExAcquireFastMutexUnsafe(&ExpEnvironmentLock);
  1274. swprintf( idString, L"Boot%04x", Id);
  1275. length = 0;
  1276. NtStatus = HalGetEnvironmentVariableEx(idString,
  1277. &EfiBootVariablesGuid,
  1278. NULL,
  1279. &length,
  1280. NULL);
  1281. if ((NtStatus == STATUS_SUCCESS) || (NtStatus == STATUS_BUFFER_TOO_SMALL)) {
  1282. //
  1283. // Delete the boot entry environment variable by writing a zero length
  1284. // value.
  1285. //
  1286. NtStatus = HalSetEnvironmentVariableEx(idString,
  1287. &EfiBootVariablesGuid,
  1288. NULL,
  1289. 0,
  1290. VARIABLE_ATTRIBUTE_NON_VOLATILE);
  1291. }
  1292. ExReleaseFastMutexUnsafe(&ExpEnvironmentLock);
  1293. KeLeaveCriticalRegion();
  1294. return NtStatus;
  1295. #endif // else !defined(EFI_NVRAM_ENABLED)
  1296. } // NtDeleteBootEntry
  1297. NTSTATUS
  1298. NtModifyBootEntry (
  1299. IN PBOOT_ENTRY BootEntry
  1300. )
  1301. /*++
  1302. Routine Description:
  1303. This function modifies an existing boot entry in the system environment.
  1304. N.B. This service requires the system environment privilege.
  1305. Arguments:
  1306. BootEntry - Supplies the address of a BOOT_ENTRY that describes the
  1307. modified boot entry. The Id field of this structure specifies the
  1308. boot entry that is to be modified.
  1309. Return Value:
  1310. STATUS_SUCCESS The function succeeded.
  1311. STATUS_INVALID_PARAMETER One of the parameters is invalid.
  1312. STATUS_NOT_IMPLEMENTED This function is not supported on this platform.
  1313. STATUS_VARIABLE_NOT_FOUND The Id specifies a boot entry that does not exist.
  1314. STATUS_UNSUCCESSFUL The firmware returned an unrecognized error.
  1315. STATUS_PRIVILEGE_NOT_HELD The caller does not have the required privilege.
  1316. STATUS_ACCESS_VIOLATION One of the input parameters cannot be read,
  1317. or one of the output parameters cannot be written.
  1318. --*/
  1319. {
  1320. return ExpSetBootEntry(FALSE, BootEntry, NULL);
  1321. } // NtModifyBootEntry
  1322. NTSTATUS
  1323. NtEnumerateBootEntries (
  1324. OUT PVOID Buffer,
  1325. IN OUT PULONG BufferLength
  1326. )
  1327. /*++
  1328. Routine Description:
  1329. This function returns a list of all existing boot entries.
  1330. N.B. This service requires the system environment privilege.
  1331. Arguments:
  1332. Buffer - Supplies the address of the buffer that is to receive the
  1333. returned data. The returned data is a sequence of BOOT_ENTRY_LIST
  1334. structures.
  1335. BufferLength - On input, supplies the length in bytes of the buffer.
  1336. On output, returns the length in bytes of the returned data.
  1337. If the input buffer is large enough, then BufferLength indicates
  1338. the amount of data copied into Buffer. If the input buffer
  1339. is too small, then BufferLength indicates the required buffer length.
  1340. Return Value:
  1341. STATUS_SUCCESS The function succeeded.
  1342. STATUS_BUFFER_TOO_SMALL The input buffer was too small.
  1343. STATUS_INVALID_PARAMETER One of the parameters is invalid.
  1344. STATUS_NOT_IMPLEMENTED This function is not supported on this platform.
  1345. STATUS_UNSUCCESSFUL The firmware returned an unrecognized error.
  1346. STATUS_PRIVILEGE_NOT_HELD The caller does not have the required privilege.
  1347. STATUS_ACCESS_VIOLATION One of the input parameters cannot be read,
  1348. or one of the output parameters cannot be written.
  1349. --*/
  1350. {
  1351. #if !defined(EFI_NVRAM_ENABLED)
  1352. UNREFERENCED_PARAMETER(Buffer);
  1353. UNREFERENCED_PARAMETER(BufferLength);
  1354. return STATUS_NOT_IMPLEMENTED;
  1355. #else
  1356. BOOLEAN HasPrivilege;
  1357. NTSTATUS NtStatus;
  1358. KPROCESSOR_MODE PreviousMode;
  1359. PCHAR LockedBuffer;
  1360. ULONG LocalBufferLength;
  1361. PVOID LockVariable;
  1362. PVARIABLE_NAME_AND_VALUE variableBuffer = NULL;
  1363. ULONG variableBufferLength;
  1364. PBOOT_ENTRY_LIST currentPtr;
  1365. PBOOT_ENTRY_LIST previousEntry;
  1366. ULONG remainingLength;
  1367. LOGICAL filling;
  1368. NTSTATUS fillStatus;
  1369. PVARIABLE_NAME_AND_VALUE variablePtr;
  1370. PWSTR maxVariablePtr;
  1371. //
  1372. // Verify that the input buffer is properly aligned.
  1373. //
  1374. if ( ALIGN_DOWN_POINTER(Buffer, ULONG) != Buffer ) {
  1375. return STATUS_INVALID_PARAMETER;
  1376. }
  1377. //
  1378. // Establish an exception handler and attempt to probe the return buffer
  1379. // and probe and read the buffer length. If the probe attempt fails, then
  1380. // return the exception code as the service status.
  1381. //
  1382. try {
  1383. //
  1384. // Get previous processor mode and probe arguments if necessary.
  1385. //
  1386. PreviousMode = KeGetPreviousMode();
  1387. if (PreviousMode != KernelMode) {
  1388. //
  1389. // Probe and capture the input buffer length.
  1390. //
  1391. ProbeForWriteUlong(BufferLength);
  1392. LocalBufferLength = *BufferLength;
  1393. //
  1394. // Probe the return buffer.
  1395. //
  1396. if (!ARGUMENT_PRESENT(Buffer)) {
  1397. LocalBufferLength = 0;
  1398. }
  1399. if (LocalBufferLength != 0) {
  1400. ProbeForWrite((PVOID)Buffer, LocalBufferLength, sizeof(ULONG));
  1401. }
  1402. //
  1403. // Check if the current thread has the privilege to query the
  1404. // system boot entry list.
  1405. //
  1406. HasPrivilege = SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege,
  1407. PreviousMode);
  1408. if (HasPrivilege == FALSE) {
  1409. return STATUS_PRIVILEGE_NOT_HELD;
  1410. }
  1411. } else {
  1412. LocalBufferLength = *BufferLength;
  1413. if (!ARGUMENT_PRESENT(Buffer)) {
  1414. LocalBufferLength = 0;
  1415. }
  1416. }
  1417. //
  1418. // If an exception occurs during the probe of the return buffer or the
  1419. // read of the input length, then always handle the exception and return
  1420. // the exception code as the status value.
  1421. //
  1422. } except (EXCEPTION_EXECUTE_HANDLER) {
  1423. return GetExceptionCode();
  1424. }
  1425. //
  1426. // Lock the caller's return buffer in memory.
  1427. //
  1428. if (LocalBufferLength != 0) {
  1429. NtStatus = ExLockUserBuffer(Buffer,
  1430. LocalBufferLength,
  1431. &LockedBuffer,
  1432. &LockVariable);
  1433. if (!NT_SUCCESS(NtStatus)) {
  1434. return NtStatus;
  1435. }
  1436. } else {
  1437. LockedBuffer = NULL;
  1438. LockVariable = NULL;
  1439. }
  1440. //
  1441. // Initialize variables for filling the output buffer.
  1442. //
  1443. currentPtr = (PBOOT_ENTRY_LIST)LockedBuffer;
  1444. remainingLength = LocalBufferLength;
  1445. filling = (LOGICAL)(remainingLength != 0);
  1446. fillStatus = STATUS_SUCCESS;
  1447. if ( !filling ) {
  1448. fillStatus = STATUS_BUFFER_TOO_SMALL;
  1449. }
  1450. previousEntry = NULL;
  1451. //
  1452. // Enumerate all existing environment variables.
  1453. //
  1454. KeEnterCriticalRegion();
  1455. ExAcquireFastMutexUnsafe(&ExpEnvironmentLock);
  1456. variableBufferLength = 0;
  1457. NtStatus = HalEnumerateEnvironmentVariablesEx(VARIABLE_INFORMATION_VALUES,
  1458. NULL,
  1459. &variableBufferLength);
  1460. if (NtStatus != STATUS_BUFFER_TOO_SMALL) {
  1461. variableBufferLength = 0;
  1462. } else {
  1463. variableBuffer = ExAllocatePoolWithTag(NonPagedPool, variableBufferLength, 'rvnE');
  1464. if (variableBuffer == NULL) {
  1465. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  1466. } else {
  1467. NtStatus = HalEnumerateEnvironmentVariablesEx(VARIABLE_INFORMATION_VALUES,
  1468. variableBuffer,
  1469. &variableBufferLength);
  1470. }
  1471. }
  1472. ExReleaseFastMutexUnsafe(&ExpEnvironmentLock);
  1473. KeLeaveCriticalRegion();
  1474. if ((NtStatus != STATUS_SUCCESS) || (variableBufferLength == 0)) {
  1475. goto done;
  1476. }
  1477. //
  1478. // Each variable whose name is of the form Boot####, where #### is a
  1479. // four-digit hex number, is assumed to define a boot entry. For
  1480. // each such variable, copy its data into the output buffer.
  1481. //
  1482. variablePtr = variableBuffer;
  1483. maxVariablePtr = (PWSTR)variableBuffer + variableBufferLength;
  1484. while (TRUE) {
  1485. ULONG id;
  1486. if ((memcmp(&variablePtr->VendorGuid, &EfiBootVariablesGuid, sizeof(GUID)) == 0) &&
  1487. ExpTranslateBootEntryNameToId(variablePtr->Name, &id) &&
  1488. (variablePtr->ValueLength >= sizeof(EFI_LOAD_OPTION))) {
  1489. PEFI_LOAD_OPTION efiLoadOption;
  1490. ULONG descriptionLength;
  1491. ULONG filePathLength;
  1492. ULONG minimumLength;
  1493. efiLoadOption = ADD_OFFSET(variablePtr, ValueOffset);
  1494. filePathLength = efiLoadOption->FilePathLength;
  1495. descriptionLength = ExpSafeWcslen(efiLoadOption->Description, maxVariablePtr);
  1496. if ( descriptionLength != 0xffffffff ) {
  1497. descriptionLength = (descriptionLength + 1) * sizeof(WCHAR);
  1498. }
  1499. minimumLength = FIELD_OFFSET(EFI_LOAD_OPTION, Description) +
  1500. descriptionLength +
  1501. filePathLength;
  1502. if ((descriptionLength != 0xffffffff) &&
  1503. (filePathLength < variablePtr->ValueLength) &&
  1504. (variablePtr->ValueLength >= minimumLength)) {
  1505. EFI_DEVICE_PATH *dp;
  1506. PUCHAR options;
  1507. ULONG optionsLength;
  1508. ULONG actualLength;
  1509. ULONG requiredLength;
  1510. ULONG friendlyNameOffset;
  1511. ULONG bootFilePathOffset;
  1512. dp = (EFI_DEVICE_PATH *)((PUCHAR)efiLoadOption->Description + descriptionLength);
  1513. options = (PUCHAR)dp + filePathLength;
  1514. optionsLength = variablePtr->ValueLength - minimumLength;
  1515. if (ALIGN_UP_POINTER(currentPtr, ULONG) != currentPtr) {
  1516. PUCHAR alignedPtr = ALIGN_UP_POINTER( currentPtr, ULONG );
  1517. ULONG fill = (ULONG)(alignedPtr - (PUCHAR)currentPtr);
  1518. currentPtr = (PBOOT_ENTRY_LIST)alignedPtr;
  1519. if (remainingLength < fill) {
  1520. filling = FALSE;
  1521. remainingLength = 0;
  1522. fillStatus = STATUS_BUFFER_TOO_SMALL;
  1523. } else {
  1524. remainingLength -= fill;
  1525. }
  1526. }
  1527. requiredLength = FIELD_OFFSET(BOOT_ENTRY, OsOptions);
  1528. requiredLength += optionsLength;
  1529. requiredLength = ALIGN_UP(requiredLength, ULONG);
  1530. friendlyNameOffset = requiredLength;
  1531. requiredLength += descriptionLength;
  1532. requiredLength = ALIGN_UP(requiredLength, ULONG);
  1533. bootFilePathOffset = requiredLength;
  1534. requiredLength += FIELD_OFFSET(FILE_PATH, FilePath);
  1535. requiredLength += filePathLength;
  1536. actualLength = requiredLength;
  1537. requiredLength += FIELD_OFFSET(BOOT_ENTRY_LIST, BootEntry);
  1538. if (remainingLength < requiredLength) {
  1539. remainingLength = 0;
  1540. filling = FALSE;
  1541. fillStatus = STATUS_BUFFER_TOO_SMALL;
  1542. } else {
  1543. remainingLength -= requiredLength;
  1544. }
  1545. if ( filling ) {
  1546. PWCHAR friendlyName;
  1547. PFILE_PATH bootFilePath;
  1548. PBOOT_ENTRY bootEntry = &currentPtr->BootEntry;
  1549. RtlZeroMemory(currentPtr, requiredLength);
  1550. bootEntry->Version = BOOT_ENTRY_VERSION;
  1551. bootEntry->Length = actualLength;
  1552. bootEntry->Id = id;
  1553. bootEntry->Attributes = 0;
  1554. if ((efiLoadOption->Attributes & LOAD_OPTION_ACTIVE) != 0) {
  1555. bootEntry->Attributes = BOOT_ENTRY_ATTRIBUTE_ACTIVE;
  1556. }
  1557. bootEntry->FriendlyNameOffset = friendlyNameOffset;
  1558. bootEntry->BootFilePathOffset = bootFilePathOffset;
  1559. bootEntry->OsOptionsLength = optionsLength;
  1560. memcpy(bootEntry->OsOptions, options, optionsLength);
  1561. if (optionsLength > FIELD_OFFSET(WINDOWS_OS_OPTIONS,OsLoadOptions)) {
  1562. PWINDOWS_OS_OPTIONS windowsOsOptions;
  1563. windowsOsOptions = (PWINDOWS_OS_OPTIONS)bootEntry->OsOptions;
  1564. if ((strcmp((char *)windowsOsOptions->Signature,
  1565. WINDOWS_OS_OPTIONS_SIGNATURE) == 0) &&
  1566. NT_SUCCESS(ExpVerifyWindowsOsOptions(windowsOsOptions,
  1567. optionsLength))) {
  1568. bootEntry->Attributes |= BOOT_ENTRY_ATTRIBUTE_WINDOWS;
  1569. }
  1570. }
  1571. friendlyName = (PWCHAR)((PUCHAR)bootEntry + friendlyNameOffset);
  1572. memcpy(friendlyName, efiLoadOption->Description, descriptionLength);
  1573. bootFilePath = (PFILE_PATH)((PUCHAR)bootEntry + bootFilePathOffset);
  1574. bootFilePath->Version = FILE_PATH_VERSION;
  1575. bootFilePath->Length = FIELD_OFFSET(FILE_PATH, FilePath) + filePathLength;
  1576. bootFilePath->Type = FILE_PATH_TYPE_EFI;
  1577. memcpy(bootFilePath->FilePath, dp, filePathLength);
  1578. if (NT_SUCCESS(ExpVerifyFilePath(bootFilePath,
  1579. ADD_OFFSET(bootFilePath, Length))) &&
  1580. ExpIsDevicePathForRemovableMedia(dp)) {
  1581. bootEntry->Attributes |= BOOT_ENTRY_ATTRIBUTE_REMOVABLE_MEDIA;
  1582. }
  1583. if ( previousEntry != NULL ) {
  1584. previousEntry->NextEntryOffset =
  1585. (ULONG)((PUCHAR)currentPtr - (PUCHAR)previousEntry);
  1586. }
  1587. previousEntry = currentPtr;
  1588. }
  1589. currentPtr = (PBOOT_ENTRY_LIST)((PUCHAR)currentPtr + requiredLength);
  1590. }
  1591. }
  1592. if (variablePtr->NextEntryOffset == 0) {
  1593. break;
  1594. }
  1595. variablePtr = ADD_OFFSET(variablePtr, NextEntryOffset);
  1596. }
  1597. if ( previousEntry != NULL ) {
  1598. previousEntry->NextEntryOffset = 0;
  1599. }
  1600. done:
  1601. //
  1602. // Free allocated pool.
  1603. //
  1604. if (variableBuffer != NULL) {
  1605. ExFreePool(variableBuffer);
  1606. }
  1607. //
  1608. // Unlock the return buffer.
  1609. //
  1610. if (LockVariable != NULL) {
  1611. ExUnlockUserBuffer(LockVariable);
  1612. }
  1613. //
  1614. // If the status of service calls is STATUS_SUCCESS, then return the fill
  1615. // status as the final status.
  1616. //
  1617. if (NT_SUCCESS(NtStatus)) {
  1618. NtStatus = fillStatus;
  1619. }
  1620. //
  1621. // Establish an exception handler and attempt to write the return length.
  1622. // If the write attempt fails, then return the exception code as the
  1623. // service status.
  1624. //
  1625. try {
  1626. //
  1627. // Write the length of the returned data.
  1628. //
  1629. *BufferLength = (ULONG)((PUCHAR)currentPtr - (PUCHAR)LockedBuffer);
  1630. return NtStatus;
  1631. //
  1632. // If an exception occurs during the write of the return length, then
  1633. // always handle the exception and return the exception code as the
  1634. // status value.
  1635. //
  1636. } except (EXCEPTION_EXECUTE_HANDLER) {
  1637. return GetExceptionCode();
  1638. }
  1639. #endif // else !defined(EFI_NVRAM_ENABLED)
  1640. } // NtEnumerateBootEntries
  1641. NTSTATUS
  1642. NtQueryBootEntryOrder (
  1643. OUT PULONG Ids,
  1644. IN OUT PULONG Count
  1645. )
  1646. /*++
  1647. Routine Description:
  1648. This function returns the system boot order list.
  1649. N.B. This service requires the system environment privilege.
  1650. Arguments:
  1651. Ids - Supplies the address of the buffer that is to receive the
  1652. returned data. The returned data is an array of ULONG boot
  1653. entry identifiers.
  1654. Count - On input, supplies the length in ULONGs of the buffer.
  1655. On output, returns the length in ULONGs of the returned data.
  1656. If the input buffer is large enough, then Count indicates
  1657. the amount of data copied into Buffer. If the input buffer
  1658. is too small, then Count indicates the required buffer length.
  1659. Return Value:
  1660. STATUS_SUCCESS The function succeeded.
  1661. STATUS_BUFFER_TOO_SMALL The input buffer was too small.
  1662. STATUS_INVALID_PARAMETER One of the parameters is invalid.
  1663. STATUS_NOT_IMPLEMENTED This function is not supported on this platform.
  1664. STATUS_UNSUCCESSFUL The firmware returned an unrecognized error.
  1665. STATUS_PRIVILEGE_NOT_HELD The caller does not have the required privilege.
  1666. STATUS_ACCESS_VIOLATION One of the input parameters cannot be read,
  1667. or one of the output parameters cannot be written.
  1668. --*/
  1669. {
  1670. #if !defined(EFI_NVRAM_ENABLED)
  1671. UNREFERENCED_PARAMETER(Ids);
  1672. UNREFERENCED_PARAMETER(Count);
  1673. return STATUS_NOT_IMPLEMENTED;
  1674. #else
  1675. BOOLEAN HasPrivilege;
  1676. NTSTATUS NtStatus;
  1677. KPROCESSOR_MODE PreviousMode;
  1678. PCHAR LockedBuffer;
  1679. ULONG LocalBufferLength;
  1680. PVOID LockVariable;
  1681. //
  1682. // Establish an exception handler and attempt to probe the return buffer
  1683. // and probe and read the buffer length. If the probe attempt fails, then
  1684. // return the exception code as the service status.
  1685. //
  1686. try {
  1687. //
  1688. // Get previous processor mode and probe arguments if necessary.
  1689. //
  1690. PreviousMode = KeGetPreviousMode();
  1691. if (PreviousMode != KernelMode) {
  1692. //
  1693. // Probe and capture the input buffer length.
  1694. //
  1695. ProbeForWriteUlong(Count);
  1696. LocalBufferLength = *Count * sizeof(ULONG);
  1697. //
  1698. // Probe the return buffer.
  1699. //
  1700. if (!ARGUMENT_PRESENT(Ids)) {
  1701. LocalBufferLength = 0;
  1702. }
  1703. if (LocalBufferLength != 0) {
  1704. ProbeForWrite((PVOID)Ids, LocalBufferLength, sizeof(ULONG));
  1705. }
  1706. //
  1707. // Check if the current thread has the privilege to query the
  1708. // system boot order list.
  1709. //
  1710. HasPrivilege = SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege,
  1711. PreviousMode);
  1712. if (HasPrivilege == FALSE) {
  1713. return STATUS_PRIVILEGE_NOT_HELD;
  1714. }
  1715. } else {
  1716. LocalBufferLength = *Count * sizeof(ULONG);
  1717. if (!ARGUMENT_PRESENT(Ids)) {
  1718. LocalBufferLength = 0;
  1719. }
  1720. }
  1721. //
  1722. // If an exception occurs during the probe of the return buffer or the
  1723. // read of the input length, then always handle the exception and return
  1724. // the exception code as the status value.
  1725. //
  1726. } except (EXCEPTION_EXECUTE_HANDLER) {
  1727. return GetExceptionCode();
  1728. }
  1729. //
  1730. // Lock the caller's return buffer in memory.
  1731. //
  1732. if (LocalBufferLength != 0) {
  1733. NtStatus = ExLockUserBuffer(Ids,
  1734. LocalBufferLength,
  1735. &LockedBuffer,
  1736. &LockVariable);
  1737. if (!NT_SUCCESS(NtStatus)) {
  1738. return NtStatus;
  1739. }
  1740. } else {
  1741. LockedBuffer = NULL;
  1742. LockVariable = NULL;
  1743. }
  1744. //
  1745. // EFI returns USHORT identifiers, which we will need to translate to
  1746. // ULONGs. Cut the buffer length in half to account for this.
  1747. //
  1748. LocalBufferLength /= 2;
  1749. //
  1750. // Query the BootOrder system environment variable.
  1751. //
  1752. KeEnterCriticalRegion();
  1753. ExAcquireFastMutexUnsafe(&ExpEnvironmentLock);
  1754. NtStatus = HalGetEnvironmentVariableEx(L"BootOrder",
  1755. &EfiBootVariablesGuid,
  1756. LockedBuffer,
  1757. &LocalBufferLength,
  1758. NULL);
  1759. ExReleaseFastMutexUnsafe(&ExpEnvironmentLock);
  1760. KeLeaveCriticalRegion();
  1761. //
  1762. // If the API succeeded, translate the returned USHORTs into ULONGs.
  1763. // Do this by converting each USHORT into a ULONG, starting from the
  1764. // end of the array to avoid stomping on needed data.
  1765. //
  1766. if (NT_SUCCESS(NtStatus)) {
  1767. ULONG count = LocalBufferLength / sizeof(USHORT);
  1768. PUSHORT sp = &((PUSHORT)LockedBuffer)[count - 1];
  1769. PULONG lp = &((PULONG)LockedBuffer)[count - 1];
  1770. while (count > 0) {
  1771. *lp-- = *sp--;
  1772. count--;
  1773. }
  1774. } else if (NtStatus == STATUS_VARIABLE_NOT_FOUND) {
  1775. //
  1776. // The BootOrder variable doesn't exist. This is unusual,
  1777. // but possible. We'll just return an empty list.
  1778. //
  1779. LocalBufferLength = 0;
  1780. NtStatus = STATUS_SUCCESS;
  1781. }
  1782. LocalBufferLength *= 2;
  1783. //
  1784. // Unlock the buffer.
  1785. //
  1786. if (LockVariable != NULL) {
  1787. ExUnlockUserBuffer(LockVariable);
  1788. }
  1789. //
  1790. // Establish an exception handler and attempt to write the return length.
  1791. // If the write attempt fails, then return the exception code as the
  1792. // service status.
  1793. //
  1794. try {
  1795. //
  1796. // Write the length of the returned data.
  1797. //
  1798. *Count = LocalBufferLength / sizeof(ULONG);
  1799. return NtStatus;
  1800. //
  1801. // If an exception occurs during the write of the return length, then
  1802. // always handle the exception and return the exception code as the
  1803. // status value.
  1804. //
  1805. } except (EXCEPTION_EXECUTE_HANDLER) {
  1806. return GetExceptionCode();
  1807. }
  1808. #endif // else !defined(EFI_NVRAM_ENABLED)
  1809. } // NtQueryBootEntryOrder
  1810. NTSTATUS
  1811. NtSetBootEntryOrder (
  1812. IN PULONG Ids,
  1813. IN ULONG Count
  1814. )
  1815. /*++
  1816. Routine Description:
  1817. This function modifies the system boot order list.
  1818. N.B. This service requires the system environment privilege.
  1819. Arguments:
  1820. Ids - Supplies the address of an array that contains the new boot
  1821. entry order list. The data is an array of ULONG identifiers.
  1822. Count - Supplies the length in ULONGs of the Ids array.
  1823. Return Value:
  1824. STATUS_SUCCESS The function succeeded.
  1825. STATUS_INVALID_PARAMETER One of the parameters is invalid.
  1826. STATUS_NOT_IMPLEMENTED This function is not supported on this platform.
  1827. STATUS_UNSUCCESSFUL The firmware returned an unrecognized error.
  1828. STATUS_PRIVILEGE_NOT_HELD The caller does not have the required privilege.
  1829. STATUS_ACCESS_VIOLATION One of the input parameters cannot be read,
  1830. or one of the output parameters cannot be written.
  1831. --*/
  1832. {
  1833. #if !defined(EFI_NVRAM_ENABLED)
  1834. UNREFERENCED_PARAMETER(Ids);
  1835. UNREFERENCED_PARAMETER(Count);
  1836. return STATUS_NOT_IMPLEMENTED;
  1837. #else
  1838. BOOLEAN HasPrivilege;
  1839. NTSTATUS NtStatus;
  1840. KPROCESSOR_MODE PreviousMode;
  1841. ULONG LocalBufferLength;
  1842. PUSHORT shortBuffer;
  1843. ULONG i;
  1844. //
  1845. // Verify that the input buffer is not empty and is not too large.
  1846. // Calculate the length in bytes of the buffer.
  1847. //
  1848. if ((Count == 0) || (Count > MAXULONG/sizeof(ULONG))) {
  1849. return STATUS_INVALID_PARAMETER;
  1850. }
  1851. LocalBufferLength = Count * sizeof(ULONG);
  1852. //
  1853. // Allocate a nonpaged buffer to hold the USHORT versions of the IDs.
  1854. //
  1855. shortBuffer = ExAllocatePoolWithTag(NonPagedPool, Count * sizeof(USHORT), 'rvnE');
  1856. if (shortBuffer == NULL) {
  1857. return STATUS_INSUFFICIENT_RESOURCES;
  1858. }
  1859. //
  1860. // Establish an exception handler and attempt to probe the input buffer.
  1861. // If the probe attempt fails, then return the exception code as the
  1862. // service status.
  1863. //
  1864. try {
  1865. //
  1866. // Get previous processor mode and probe arguments if necessary.
  1867. //
  1868. PreviousMode = KeGetPreviousMode();
  1869. if (PreviousMode != KernelMode) {
  1870. //
  1871. // Probe the input buffer.
  1872. //
  1873. ProbeForRead((PVOID)Ids, LocalBufferLength, sizeof(ULONG));
  1874. //
  1875. // Check if the current thread has the privilege to modify the
  1876. // system boot order list.
  1877. //
  1878. HasPrivilege = SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege,
  1879. PreviousMode);
  1880. if (HasPrivilege == FALSE) {
  1881. ExFreePool(shortBuffer);
  1882. return STATUS_PRIVILEGE_NOT_HELD;
  1883. }
  1884. }
  1885. //
  1886. // Truncate the ULONGs in the input buffer into USHORTs in
  1887. // the local buffer.
  1888. //
  1889. for ( i = 0; i < Count; i++ ) {
  1890. if (Ids[i] > MAXUSHORT) {
  1891. ExFreePool(shortBuffer);
  1892. return STATUS_INVALID_PARAMETER;
  1893. }
  1894. shortBuffer[i] = (USHORT)Ids[i];
  1895. }
  1896. //
  1897. // If an exception occurs during the probe of the input buffer, then
  1898. // always handle the exception and return the exception code as the
  1899. // status value.
  1900. //
  1901. } except (EXCEPTION_EXECUTE_HANDLER) {
  1902. ExFreePool(shortBuffer);
  1903. return GetExceptionCode();
  1904. }
  1905. //
  1906. // Set the BootOrder system environment variable.
  1907. //
  1908. KeEnterCriticalRegion();
  1909. ExAcquireFastMutexUnsafe(&ExpEnvironmentLock);
  1910. NtStatus = HalSetEnvironmentVariableEx(L"BootOrder",
  1911. &EfiBootVariablesGuid,
  1912. shortBuffer,
  1913. Count * sizeof(USHORT),
  1914. VARIABLE_ATTRIBUTE_NON_VOLATILE);
  1915. ExReleaseFastMutexUnsafe(&ExpEnvironmentLock);
  1916. KeLeaveCriticalRegion();
  1917. ExFreePool(shortBuffer);
  1918. return NtStatus;
  1919. #endif // else !defined(EFI_NVRAM_ENABLED)
  1920. } // NtSetBootEntryOrder
  1921. NTSTATUS
  1922. NtQueryBootOptions (
  1923. OUT PBOOT_OPTIONS BootOptions,
  1924. IN OUT PULONG BootOptionsLength
  1925. )
  1926. /*++
  1927. Routine Description:
  1928. This function returns the system's global boot options.
  1929. N.B. This service requires the system environment privilege.
  1930. Arguments:
  1931. BootOptions - Supplies the address of the buffer that is to receive the
  1932. returned data.
  1933. BootOptionsLength - On input, supplies the length in bytes of the buffer.
  1934. On output, returns the length in bytes of the returned data.
  1935. If the input buffer is large enough, then BootOptionsLength indicates
  1936. the amount of data copied into BootOptions. If the input buffer
  1937. is too small, then BootOptionsLength indicates the required buffer
  1938. length.
  1939. Return Value:
  1940. STATUS_SUCCESS The function succeeded.
  1941. STATUS_BUFFER_TOO_SMALL The input buffer was too small.
  1942. STATUS_INVALID_PARAMETER One of the parameters is invalid.
  1943. STATUS_NOT_IMPLEMENTED This function is not supported on this platform.
  1944. STATUS_UNSUCCESSFUL The firmware returned an unrecognized error.
  1945. STATUS_PRIVILEGE_NOT_HELD The caller does not have the required privilege.
  1946. STATUS_ACCESS_VIOLATION One of the input parameters cannot be read,
  1947. or one of the output parameters cannot be written.
  1948. --*/
  1949. {
  1950. #if !defined(EFI_NVRAM_ENABLED)
  1951. UNREFERENCED_PARAMETER(BootOptions);
  1952. UNREFERENCED_PARAMETER(BootOptionsLength);
  1953. return STATUS_NOT_IMPLEMENTED;
  1954. #else
  1955. BOOLEAN HasPrivilege;
  1956. NTSTATUS NtStatus;
  1957. KPROCESSOR_MODE PreviousMode;
  1958. ULONG LocalBufferLength;
  1959. ULONG Timeout = 0;
  1960. ULONG BootCurrent = 0;
  1961. ULONG BootNext = 0;
  1962. ULONG VariableLength;
  1963. ULONG requiredLength;
  1964. //
  1965. // Establish an exception handler and attempt to probe the return buffer
  1966. // and probe and read the buffer length. If the probe attempt fails, then
  1967. // return the exception code as the service status.
  1968. //
  1969. try {
  1970. //
  1971. // Get previous processor mode and probe arguments if necessary.
  1972. //
  1973. PreviousMode = KeGetPreviousMode();
  1974. if (PreviousMode != KernelMode) {
  1975. //
  1976. // Probe and capture the input buffer length.
  1977. //
  1978. ProbeForWriteUlong(BootOptionsLength);
  1979. LocalBufferLength = *BootOptionsLength;
  1980. //
  1981. // Probe the return buffer.
  1982. //
  1983. if (!ARGUMENT_PRESENT(BootOptions)) {
  1984. LocalBufferLength = 0;
  1985. }
  1986. if (LocalBufferLength != 0) {
  1987. ProbeForWrite((PVOID)BootOptions, LocalBufferLength, sizeof(ULONG));
  1988. }
  1989. //
  1990. // Check if the current thread has the privilege to query the
  1991. // system boot order list.
  1992. //
  1993. HasPrivilege = SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege,
  1994. PreviousMode);
  1995. if (HasPrivilege == FALSE) {
  1996. return STATUS_PRIVILEGE_NOT_HELD;
  1997. }
  1998. } else {
  1999. LocalBufferLength = *BootOptionsLength;
  2000. if (!ARGUMENT_PRESENT(BootOptions)) {
  2001. LocalBufferLength = 0;
  2002. }
  2003. }
  2004. //
  2005. // If an exception occurs during the probe of the return buffer or the
  2006. // read of the input length, then always handle the exception and return
  2007. // the exception code as the status value.
  2008. //
  2009. } except (EXCEPTION_EXECUTE_HANDLER) {
  2010. return GetExceptionCode();
  2011. }
  2012. //
  2013. // Verify that the input buffer is big enough. IA64 always returns
  2014. // HeadlessRedirection as a null string, so we know the required
  2015. // length up front.
  2016. //
  2017. requiredLength = FIELD_OFFSET(BOOT_OPTIONS,HeadlessRedirection) + sizeof(WCHAR);
  2018. if (LocalBufferLength < requiredLength) {
  2019. NtStatus = STATUS_BUFFER_TOO_SMALL;
  2020. goto done;
  2021. }
  2022. //
  2023. // Query the following system environment variables: Timeout, BootCurrent,
  2024. // and BootNext.
  2025. //
  2026. // NB: Some machines seem to have their Timeout variable set as a ULONG
  2027. // instead of a USHORT. Since we have ULONG buffers for the variables that
  2028. // we're querying, we'll pass in the full length of the buffer, even though
  2029. // we only expect to get back a USHORT. And we'll also be prepared for an
  2030. // even bigger variable to exist. If the variable is bigger, then we'll
  2031. // return a default value for the variable.
  2032. //
  2033. KeEnterCriticalRegion();
  2034. ExAcquireFastMutexUnsafe(&ExpEnvironmentLock);
  2035. VariableLength = 4;
  2036. NtStatus = HalGetEnvironmentVariableEx(L"Timeout",
  2037. &EfiBootVariablesGuid,
  2038. &Timeout,
  2039. &VariableLength,
  2040. NULL);
  2041. switch (NtStatus) {
  2042. case STATUS_SUCCESS:
  2043. if (VariableLength > 2) {
  2044. if (Timeout == 0xffffffff) {
  2045. Timeout = 0xffff;
  2046. } else if (Timeout > 0xffff) {
  2047. Timeout = 0xfffe;
  2048. }
  2049. }
  2050. if ( Timeout == 0xffff ) {
  2051. Timeout = 0xffffffff;
  2052. }
  2053. break;
  2054. case STATUS_VARIABLE_NOT_FOUND:
  2055. Timeout = 0xffffffff;
  2056. break;
  2057. case STATUS_BUFFER_TOO_SMALL:
  2058. Timeout = 0xfffffffe;
  2059. break;
  2060. default:
  2061. goto done_unlock;
  2062. }
  2063. VariableLength = 4;
  2064. NtStatus = HalGetEnvironmentVariableEx(L"BootCurrent",
  2065. &EfiBootVariablesGuid,
  2066. &BootCurrent,
  2067. &VariableLength,
  2068. NULL);
  2069. switch (NtStatus) {
  2070. case STATUS_SUCCESS:
  2071. if (VariableLength > 2) {
  2072. BootCurrent &= 0xffff;
  2073. }
  2074. break;
  2075. case STATUS_VARIABLE_NOT_FOUND:
  2076. case STATUS_BUFFER_TOO_SMALL:
  2077. BootCurrent = 0xfffffffe;
  2078. break;
  2079. default:
  2080. goto done_unlock;
  2081. }
  2082. VariableLength = 2;
  2083. NtStatus = HalGetEnvironmentVariableEx(L"BootNext",
  2084. &EfiBootVariablesGuid,
  2085. &BootNext,
  2086. &VariableLength,
  2087. NULL);
  2088. switch (NtStatus) {
  2089. case STATUS_SUCCESS:
  2090. if (VariableLength > 2) {
  2091. BootNext &= 0xffff;
  2092. }
  2093. break;
  2094. case STATUS_VARIABLE_NOT_FOUND:
  2095. case STATUS_BUFFER_TOO_SMALL:
  2096. BootNext = 0xfffffffe;
  2097. NtStatus = STATUS_SUCCESS;
  2098. break;
  2099. default:
  2100. goto done_unlock;
  2101. }
  2102. done_unlock:
  2103. ExReleaseFastMutexUnsafe(&ExpEnvironmentLock);
  2104. KeLeaveCriticalRegion();
  2105. done:
  2106. //
  2107. // Establish an exception handler and attempt to write the output buffer
  2108. // and the return length. If the write attempt fails, then return the
  2109. // exception code as the service status.
  2110. //
  2111. try {
  2112. //
  2113. // Write the output buffer.
  2114. //
  2115. if ((NtStatus == STATUS_SUCCESS) && ARGUMENT_PRESENT(BootOptions)) {
  2116. BootOptions->Version = BOOT_OPTIONS_VERSION;
  2117. BootOptions->Length = (FIELD_OFFSET(BOOT_OPTIONS,HeadlessRedirection) + sizeof(WCHAR));
  2118. BootOptions->Timeout = Timeout;
  2119. BootOptions->CurrentBootEntryId = BootCurrent;
  2120. BootOptions->NextBootEntryId = BootNext;
  2121. BootOptions->HeadlessRedirection[0] = 0;
  2122. }
  2123. //
  2124. // Write the return length.
  2125. //
  2126. *BootOptionsLength = requiredLength;
  2127. return NtStatus;
  2128. //
  2129. // If an exception occurs during the write of the return data, then
  2130. // always handle the exception and return the exception code as the
  2131. // status value.
  2132. //
  2133. } except (EXCEPTION_EXECUTE_HANDLER) {
  2134. return GetExceptionCode();
  2135. }
  2136. #endif // else !defined(EFI_NVRAM_ENABLED)
  2137. } // NtQueryBootOptions
  2138. NTSTATUS
  2139. NtSetBootOptions (
  2140. IN PBOOT_OPTIONS BootOptions,
  2141. IN ULONG FieldsToChange
  2142. )
  2143. /*++
  2144. Routine Description:
  2145. This function modifies the system's global boot options.
  2146. N.B. This service requires the system environment privilege.
  2147. Arguments:
  2148. BootOptions - Supplies the address of the buffer that contains the new
  2149. boot options.
  2150. FieldsToChange - Supplies a bit mask indicating with fields in BootOptions
  2151. are to be used to modify global boot options.
  2152. Return Value:
  2153. STATUS_SUCCESS The function succeeded.
  2154. STATUS_INVALID_PARAMETER One of the parameters is invalid.
  2155. STATUS_NOT_IMPLEMENTED This function is not supported on this platform.
  2156. STATUS_UNSUCCESSFUL The firmware returned an unrecognized error.
  2157. STATUS_PRIVILEGE_NOT_HELD The caller does not have the required privilege.
  2158. STATUS_ACCESS_VIOLATION One of the input parameters cannot be read,
  2159. or one of the output parameters cannot be written.
  2160. --*/
  2161. {
  2162. #if !defined(EFI_NVRAM_ENABLED)
  2163. UNREFERENCED_PARAMETER(BootOptions);
  2164. UNREFERENCED_PARAMETER(FieldsToChange);
  2165. return STATUS_NOT_IMPLEMENTED;
  2166. #else
  2167. BOOLEAN HasPrivilege;
  2168. NTSTATUS NtStatus;
  2169. KPROCESSOR_MODE PreviousMode;
  2170. ULONG LocalBufferLength;
  2171. ULONG Timeout = 0;
  2172. ULONG BootNext = 0;
  2173. //
  2174. // Establish an exception handler and attempt to probe and validate the
  2175. // input buffer. If the probe attempt fails, then return the exception
  2176. // code as the service status.
  2177. //
  2178. try {
  2179. //
  2180. // Verify that the input buffer is big enough. It must extend at
  2181. // least to the HeadlessRedirection field.
  2182. //
  2183. PreviousMode = KeGetPreviousMode();
  2184. if (PreviousMode != KernelMode) {
  2185. LocalBufferLength = ProbeAndReadUlong(&BootOptions->Length);
  2186. } else {
  2187. LocalBufferLength = BootOptions->Length;
  2188. }
  2189. if (LocalBufferLength < FIELD_OFFSET(BOOT_OPTIONS,HeadlessRedirection)) {
  2190. return STATUS_INVALID_PARAMETER;
  2191. }
  2192. //
  2193. // Get previous processor mode and probe arguments if necessary.
  2194. //
  2195. if (PreviousMode != KernelMode) {
  2196. //
  2197. // Probe the input buffer.
  2198. //
  2199. ProbeForRead((PVOID)BootOptions, LocalBufferLength, sizeof(ULONG));
  2200. //
  2201. // Check if the current thread has the privilege to query the
  2202. // system boot order list.
  2203. //
  2204. HasPrivilege = SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege,
  2205. PreviousMode);
  2206. if (HasPrivilege == FALSE) {
  2207. return STATUS_PRIVILEGE_NOT_HELD;
  2208. }
  2209. }
  2210. //
  2211. // Verify the structure version.
  2212. //
  2213. if ((BootOptions->Version == 0) ||
  2214. (BootOptions->Version > BOOT_OPTIONS_VERSION)) {
  2215. return STATUS_INVALID_PARAMETER;
  2216. }
  2217. //
  2218. // Capture the Timeout and BootNext fields.
  2219. //
  2220. Timeout = BootOptions->Timeout;
  2221. BootNext = BootOptions->NextBootEntryId;
  2222. //
  2223. // If an exception occurs during the probe and capture of the input buffer,
  2224. // then always handle the exception and return the exception code as the
  2225. // status value.
  2226. //
  2227. } except (EXCEPTION_EXECUTE_HANDLER) {
  2228. return GetExceptionCode();
  2229. }
  2230. //
  2231. // If requested, set the Timeout and BootNext system environment variables.
  2232. //
  2233. if ((FieldsToChange & BOOT_OPTIONS_FIELD_NEXT_BOOT_ENTRY_ID) != 0) {
  2234. if (BootNext > MAXUSHORT) {
  2235. return STATUS_INVALID_PARAMETER;
  2236. }
  2237. }
  2238. KeEnterCriticalRegion();
  2239. ExAcquireFastMutexUnsafe(&ExpEnvironmentLock);
  2240. NtStatus = STATUS_SUCCESS;
  2241. if ((FieldsToChange & BOOT_OPTIONS_FIELD_TIMEOUT) != 0) {
  2242. if (Timeout == 0xffffffff) {
  2243. Timeout = 0xffff;
  2244. } else if (Timeout > 0xfffe) {
  2245. Timeout = 0xfffe;
  2246. }
  2247. NtStatus = HalSetEnvironmentVariableEx(L"Timeout",
  2248. &EfiBootVariablesGuid,
  2249. &Timeout,
  2250. 2,
  2251. VARIABLE_ATTRIBUTE_NON_VOLATILE);
  2252. }
  2253. if (NT_SUCCESS(NtStatus) &&
  2254. ((FieldsToChange & BOOT_OPTIONS_FIELD_NEXT_BOOT_ENTRY_ID) != 0)) {
  2255. NtStatus = HalSetEnvironmentVariableEx(L"BootNext",
  2256. &EfiBootVariablesGuid,
  2257. &BootNext,
  2258. 2,
  2259. VARIABLE_ATTRIBUTE_NON_VOLATILE);
  2260. }
  2261. ExReleaseFastMutexUnsafe(&ExpEnvironmentLock);
  2262. KeLeaveCriticalRegion();
  2263. return NtStatus;
  2264. #endif // else !defined(EFI_NVRAM_ENABLED)
  2265. } // NtSetBootOptions
  2266. NTSTATUS
  2267. NtTranslateFilePath (
  2268. IN PFILE_PATH InputFilePath,
  2269. IN ULONG OutputType,
  2270. OUT PFILE_PATH OutputFilePath,
  2271. IN OUT PULONG OutputFilePathLength
  2272. )
  2273. /*++
  2274. Routine Description:
  2275. This function translates a FILE_PATH from one format to another.
  2276. Arguments:
  2277. InputFilePath - Supplies the address of the buffer that contains the
  2278. FILE_PATH that is to be translated.
  2279. OutputType - Specifies the desired output file path type. One of
  2280. FILE_PATH_TYPE_ARC, FILE_PATH_TYPE_ARC_SIGNATURE, FILE_PATH_TYPE_NT,
  2281. and FILE_PATH_TYPE_EFI.
  2282. Return Value:
  2283. STATUS_SUCCESS The function succeeded.
  2284. STATUS_INVALID_PARAMETER One of the parameters is invalid.
  2285. STATUS_NOT_IMPLEMENTED This function is not supported on this platform.
  2286. STATUS_UNSUCCESSFUL The firmware returned an unrecognized error.
  2287. STATUS_PRIVILEGE_NOT_HELD The caller does not have the required privilege.
  2288. STATUS_ACCESS_VIOLATION One of the input parameters cannot be read,
  2289. or one of the output parameters cannot be written.
  2290. --*/
  2291. {
  2292. #if !defined(EFI_NVRAM_ENABLED)
  2293. UNREFERENCED_PARAMETER(InputFilePath);
  2294. UNREFERENCED_PARAMETER(OutputType);
  2295. UNREFERENCED_PARAMETER(OutputFilePath);
  2296. UNREFERENCED_PARAMETER(OutputFilePathLength);
  2297. return STATUS_NOT_IMPLEMENTED;
  2298. #else
  2299. BOOLEAN HasPrivilege;
  2300. NTSTATUS status;
  2301. KPROCESSOR_MODE PreviousMode;
  2302. ULONG localInputPathLength;
  2303. ULONG localOutputPathLength;
  2304. PFILE_PATH localInputPath = NULL;
  2305. PFILE_PATH localOutputPath;
  2306. //
  2307. // Verify the output type.
  2308. //
  2309. if ((OutputType < FILE_PATH_TYPE_MIN) ||
  2310. (OutputType > FILE_PATH_TYPE_MAX)) {
  2311. //DbgPrint( "NtTranslateFilePath: OutputType outside range\n" );
  2312. return STATUS_INVALID_PARAMETER;
  2313. }
  2314. //
  2315. // Establish an exception handler and attempt to probe and read the
  2316. // input buffer, and probe the output buffer and the output length. If
  2317. // the probe attempt fails, then return the exception code as the service
  2318. // status.
  2319. //
  2320. try {
  2321. //
  2322. // Verify that the input buffer is big enough. It must extend at
  2323. // least to the FilePath field.
  2324. //
  2325. PreviousMode = KeGetPreviousMode();
  2326. if (PreviousMode != KernelMode) {
  2327. localInputPathLength = ProbeAndReadUlong(&InputFilePath->Length);
  2328. } else {
  2329. localInputPathLength = InputFilePath->Length;
  2330. }
  2331. if (localInputPathLength < FIELD_OFFSET(FILE_PATH,FilePath)) {
  2332. //DbgPrint( "NtTranslateFilePath: input buffer too short\n" );
  2333. return STATUS_INVALID_PARAMETER;
  2334. }
  2335. //
  2336. // Get previous processor mode and probe arguments if necessary.
  2337. //
  2338. if (PreviousMode != KernelMode) {
  2339. //
  2340. // Probe the input buffer.
  2341. //
  2342. ProbeForRead((PVOID)InputFilePath, localInputPathLength, sizeof(ULONG));
  2343. //
  2344. // Probe and capture the output length.
  2345. //
  2346. ProbeForWriteUlong(OutputFilePathLength);
  2347. localOutputPathLength = *OutputFilePathLength;
  2348. //
  2349. // Probe the output buffer.
  2350. //
  2351. if (!ARGUMENT_PRESENT(OutputFilePath)) {
  2352. localOutputPathLength = 0;
  2353. }
  2354. if (localOutputPathLength != 0) {
  2355. ProbeForWrite((PVOID)OutputFilePath, localOutputPathLength, sizeof(ULONG));
  2356. }
  2357. //
  2358. // Check if the current thread has the privilege to query the
  2359. // system boot order list.
  2360. //
  2361. HasPrivilege = SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege,
  2362. PreviousMode);
  2363. if (HasPrivilege == FALSE) {
  2364. return STATUS_PRIVILEGE_NOT_HELD;
  2365. }
  2366. } else {
  2367. localOutputPathLength = *OutputFilePathLength;
  2368. if (!ARGUMENT_PRESENT(OutputFilePath)) {
  2369. localOutputPathLength = 0;
  2370. }
  2371. }
  2372. //
  2373. // Allocate a nonpaged buffer to hold a copy of the input buffer.
  2374. // Copy the input buffer into the local buffer.
  2375. //
  2376. localInputPath = ExAllocatePoolWithTag(NonPagedPool, localInputPathLength, 'rvnE');
  2377. if (localInputPath == NULL) {
  2378. return STATUS_INSUFFICIENT_RESOURCES;
  2379. }
  2380. RtlCopyMemory(localInputPath, InputFilePath, localInputPathLength);
  2381. //
  2382. // Allocate a nonpaged buffer into which to build the output path.
  2383. //
  2384. if (localOutputPathLength != 0) {
  2385. localOutputPath = ExAllocatePoolWithTag(NonPagedPool, localOutputPathLength, 'rvnE');
  2386. if (localOutputPath == NULL) {
  2387. ExFreePool(localInputPath);
  2388. localInputPath = NULL;
  2389. return STATUS_INSUFFICIENT_RESOURCES;
  2390. }
  2391. } else {
  2392. localOutputPath = NULL;
  2393. }
  2394. //
  2395. // If an exception occurs during the probe and capture of the input buffer,
  2396. // then always handle the exception and return the exception code as the
  2397. // status value.
  2398. //
  2399. } except (EXCEPTION_EXECUTE_HANDLER) {
  2400. if (localInputPath != NULL) {
  2401. ExFreePool(localInputPath);
  2402. }
  2403. return GetExceptionCode();
  2404. }
  2405. //
  2406. // Verify the format of the input file path.
  2407. //
  2408. status = ExpVerifyFilePath(localInputPath, ADD_OFFSET(localInputPath, Length));
  2409. if (NT_SUCCESS(status)) {
  2410. //
  2411. // If the output type is the same as the input type, just copy the input
  2412. // path to the output path.
  2413. //
  2414. if (OutputType == localInputPath->Type) {
  2415. if (localOutputPathLength >= localInputPathLength) {
  2416. RtlCopyMemory(localOutputPath, localInputPath, localInputPathLength);
  2417. } else {
  2418. status = STATUS_BUFFER_TOO_SMALL;
  2419. }
  2420. localOutputPathLength = localInputPathLength;
  2421. } else {
  2422. //
  2423. // Conversion is required.
  2424. //
  2425. switch (localInputPath->Type) {
  2426. case FILE_PATH_TYPE_ARC:
  2427. case FILE_PATH_TYPE_ARC_SIGNATURE:
  2428. status = ExpTranslateArcPath(
  2429. localInputPath,
  2430. OutputType,
  2431. localOutputPath,
  2432. &localOutputPathLength
  2433. );
  2434. break;
  2435. case FILE_PATH_TYPE_NT:
  2436. status = ExpTranslateNtPath(
  2437. localInputPath,
  2438. OutputType,
  2439. localOutputPath,
  2440. &localOutputPathLength);
  2441. break;
  2442. case FILE_PATH_TYPE_EFI:
  2443. status = ExpTranslateEfiPath(
  2444. localInputPath,
  2445. OutputType,
  2446. localOutputPath,
  2447. &localOutputPathLength);
  2448. break;
  2449. default:
  2450. ASSERT(FALSE);
  2451. //DbgPrint( "NtTranslateFilePath: input type outside range\n" );
  2452. status = STATUS_INVALID_PARAMETER;
  2453. break;
  2454. }
  2455. }
  2456. }
  2457. ExFreePool(localInputPath);
  2458. //
  2459. // Establish an exception handler and attempt to copy to the output
  2460. // buffer and write the output length. If the write attempt fails, then
  2461. // return the exception code as the service status.
  2462. //
  2463. try {
  2464. //
  2465. // Copy the output path.
  2466. //
  2467. if (NT_SUCCESS(status) && (localOutputPath != NULL)) {
  2468. RtlCopyMemory(OutputFilePath, localOutputPath, localOutputPathLength);
  2469. }
  2470. if (localOutputPath != NULL) {
  2471. ExFreePool(localOutputPath);
  2472. localOutputPath = NULL;
  2473. }
  2474. //
  2475. // Write the output length.
  2476. //
  2477. if (ARGUMENT_PRESENT(OutputFilePathLength)) {
  2478. *OutputFilePathLength = localOutputPathLength;
  2479. }
  2480. return status;
  2481. //
  2482. // If an exception occurs during the write of the return data, then
  2483. // always handle the exception and return the exception code as the
  2484. // status value.
  2485. //
  2486. } except (EXCEPTION_EXECUTE_HANDLER) {
  2487. if (localOutputPath != NULL) {
  2488. ExFreePool(localOutputPath);
  2489. }
  2490. return GetExceptionCode();
  2491. }
  2492. #endif // else !defined(EFI_NVRAM_ENABLED)
  2493. } // NtTranslateFilePath
  2494. NTSTATUS
  2495. ExpSetBootEntry (
  2496. IN LOGICAL CreateNewEntry,
  2497. IN PBOOT_ENTRY BootEntry,
  2498. OUT PULONG Id OPTIONAL
  2499. )
  2500. /*++
  2501. Routine Description:
  2502. This function adds a boot entry to the system environment or modifies
  2503. an existing boot entry. It is a local routine called by NtAddBootEntry
  2504. and NtModifyBootEntry.
  2505. N.B. This function requires the system environment privilege.
  2506. Arguments:
  2507. CreateNewEntry - Indicates whether this function is to add a new boot
  2508. entry (TRUE - NtAddBootEntry), or modify an existing boot entry
  2509. (FALSE - NtModifyBootEntry).
  2510. BootEntry - Supplies the address of a BOOT_ENTRY that describes the
  2511. new boot entry.
  2512. Id - Supplies the address of a ULONG that is to receive the identifier
  2513. assigned to the new boot entry.
  2514. Return Value:
  2515. STATUS_SUCCESS The function succeeded.
  2516. STATUS_INVALID_PARAMETER One of the parameters is invalid.
  2517. STATUS_NOT_IMPLEMENTED This function is not supported on this platform.
  2518. STATUS_UNSUCCESSFUL The firmware returned an unrecognized error.
  2519. STATUS_PRIVILEGE_NOT_HELD The caller does not have the required privilege.
  2520. STATUS_ACCESS_VIOLATION One of the input parameters cannot be read,
  2521. or one of the output parameters cannot be written.
  2522. --*/
  2523. {
  2524. #if !defined(EFI_NVRAM_ENABLED)
  2525. UNREFERENCED_PARAMETER(CreateNewEntry);
  2526. UNREFERENCED_PARAMETER(BootEntry);
  2527. UNREFERENCED_PARAMETER(Id);
  2528. return STATUS_NOT_IMPLEMENTED;
  2529. #else
  2530. BOOLEAN HasPrivilege;
  2531. NTSTATUS NtStatus;
  2532. KPROCESSOR_MODE PreviousMode;
  2533. PBOOT_ENTRY localBootEntry = NULL;
  2534. ULONG LocalBufferLength;
  2535. PUCHAR MaxBuffer;
  2536. ULONG id = 0;
  2537. WCHAR idString[9];
  2538. PWCHAR friendlyName;
  2539. ULONG friendlyNameLength;
  2540. PFILE_PATH bootFilePath = NULL;
  2541. PFILE_PATH translatedBootFilePath = NULL;
  2542. LOGICAL isWindowsOs;
  2543. PWINDOWS_OS_OPTIONS windowsOsOptions;
  2544. PFILE_PATH windowsFilePath;
  2545. PEFI_LOAD_OPTION efiLoadOption = NULL;
  2546. PUCHAR efiBootFilePath;
  2547. ULONG efiBootFilePathLength;
  2548. ULONG efiWindowsFilePathLength;
  2549. ULONG osOptionsLength;
  2550. ULONG length;
  2551. ULONG requiredLength;
  2552. PUCHAR efiOsOptions;
  2553. //
  2554. // Establish an exception handler and attempt to probe and read the
  2555. // input buffer, and probe the output identifier parameter. If the probe
  2556. // attempt fails, then return the exception code as the service status.
  2557. //
  2558. try {
  2559. //
  2560. // Verify that the input buffer is big enough. It must extend at
  2561. // least to the OsOptions field.
  2562. //
  2563. PreviousMode = KeGetPreviousMode();
  2564. if (PreviousMode != KernelMode) {
  2565. LocalBufferLength = ProbeAndReadUlong(&BootEntry->Length);
  2566. } else {
  2567. LocalBufferLength = BootEntry->Length;
  2568. }
  2569. if (LocalBufferLength < FIELD_OFFSET(BOOT_ENTRY,OsOptions)) {
  2570. return STATUS_INVALID_PARAMETER;
  2571. }
  2572. //
  2573. // Get previous processor mode and probe arguments if necessary.
  2574. //
  2575. if (PreviousMode != KernelMode) {
  2576. //
  2577. // Probe the input buffer.
  2578. //
  2579. ProbeForRead((PVOID)BootEntry, LocalBufferLength, sizeof(ULONG));
  2580. //
  2581. // Probe the output identifier.
  2582. //
  2583. if (ARGUMENT_PRESENT(Id)) {
  2584. ProbeForWriteUlong(Id);
  2585. }
  2586. //
  2587. // Check if the current thread has the privilege to query the
  2588. // system boot order list.
  2589. //
  2590. HasPrivilege = SeSinglePrivilegeCheck(SeSystemEnvironmentPrivilege,
  2591. PreviousMode);
  2592. if (HasPrivilege == FALSE) {
  2593. return STATUS_PRIVILEGE_NOT_HELD;
  2594. }
  2595. }
  2596. //
  2597. // Allocate a nonpaged buffer to hold a copy of the input buffer.
  2598. // Copy the input buffer into the local buffer.
  2599. //
  2600. localBootEntry = ExAllocatePoolWithTag(NonPagedPool, LocalBufferLength, 'rvnE');
  2601. if (localBootEntry == NULL) {
  2602. return STATUS_INSUFFICIENT_RESOURCES;
  2603. }
  2604. RtlCopyMemory(localBootEntry, BootEntry, LocalBufferLength);
  2605. //
  2606. // If an exception occurs during the probe and capture of the input buffer,
  2607. // then always handle the exception and return the exception code as the
  2608. // status value.
  2609. //
  2610. } except (EXCEPTION_EXECUTE_HANDLER) {
  2611. if (localBootEntry != NULL) {
  2612. ExFreePool(localBootEntry);
  2613. }
  2614. return GetExceptionCode();
  2615. }
  2616. //
  2617. // Calculate the address of the byte above the end of the local buffer.
  2618. //
  2619. MaxBuffer = (PUCHAR)localBootEntry + LocalBufferLength;
  2620. //
  2621. // Verify the structure version.
  2622. //
  2623. if ((localBootEntry->Version == 0) ||
  2624. (localBootEntry->Version > BOOT_ENTRY_VERSION)) {
  2625. NtStatus = STATUS_INVALID_PARAMETER;
  2626. goto done;
  2627. }
  2628. //
  2629. // If modifying an existing entry, verify that the input identifier is
  2630. // in range.
  2631. //
  2632. if (!CreateNewEntry && (localBootEntry->Id > MAXUSHORT)) {
  2633. NtStatus = STATUS_INVALID_PARAMETER;
  2634. goto done;
  2635. }
  2636. //
  2637. // Ignore boot entry attributes that can't be set.
  2638. //
  2639. localBootEntry->Attributes &= BOOT_ENTRY_ATTRIBUTE_VALID_BITS;
  2640. //
  2641. // Verify that offsets are aligned correctly.
  2642. //
  2643. if (((localBootEntry->FriendlyNameOffset & (sizeof(WCHAR) - 1)) != 0) ||
  2644. ((localBootEntry->BootFilePathOffset & (sizeof(ULONG) - 1)) != 0)) {
  2645. NtStatus = STATUS_INVALID_PARAMETER;
  2646. goto done;
  2647. }
  2648. //
  2649. // Verify that OsOptions doesn't extend beyond the end of the buffer.
  2650. //
  2651. if ((localBootEntry->OsOptionsLength > LocalBufferLength) ||
  2652. ((localBootEntry->OsOptions + localBootEntry->OsOptionsLength) >= MaxBuffer)) {
  2653. NtStatus = STATUS_INVALID_PARAMETER;
  2654. goto done;
  2655. }
  2656. //
  2657. // If the OsOptions are for a Windows operating system, verify them.
  2658. //
  2659. windowsOsOptions = (PWINDOWS_OS_OPTIONS)localBootEntry->OsOptions;
  2660. if ((localBootEntry->OsOptionsLength >= FIELD_OFFSET(WINDOWS_OS_OPTIONS,Version)) &&
  2661. (strcmp((char *)windowsOsOptions->Signature, WINDOWS_OS_OPTIONS_SIGNATURE) == 0)) {
  2662. if (localBootEntry->OsOptionsLength <= FIELD_OFFSET(WINDOWS_OS_OPTIONS,OsLoadOptions)) {
  2663. NtStatus = STATUS_INVALID_PARAMETER;
  2664. goto done;
  2665. }
  2666. NtStatus = ExpVerifyWindowsOsOptions(windowsOsOptions,
  2667. localBootEntry->OsOptionsLength);
  2668. if (!NT_SUCCESS(NtStatus)) {
  2669. goto done;
  2670. }
  2671. isWindowsOs = TRUE;
  2672. windowsFilePath = ADD_OFFSET(windowsOsOptions, OsLoadPathOffset);
  2673. } else {
  2674. isWindowsOs = FALSE;
  2675. windowsFilePath = NULL; // keep the compiler quiet
  2676. }
  2677. //
  2678. // Verify that FriendlyName doesn't extend beyond the end of the buffer.
  2679. //
  2680. friendlyName = ADD_OFFSET(localBootEntry, FriendlyNameOffset);
  2681. if ((friendlyNameLength = ExpSafeWcslen(friendlyName, (PWSTR)MaxBuffer)) == 0xffffffff) {
  2682. NtStatus = STATUS_INVALID_PARAMETER;
  2683. goto done;
  2684. }
  2685. //
  2686. // Convert friendlyNameLength from a character count into a byte count,
  2687. // including the null terminator.
  2688. //
  2689. friendlyNameLength = (friendlyNameLength + 1) * sizeof(WCHAR);
  2690. //
  2691. // Verify that BootFilePath is valid and doesn't extend beyond the end of
  2692. // the buffer.
  2693. //
  2694. bootFilePath = ADD_OFFSET(localBootEntry, BootFilePathOffset);
  2695. NtStatus = ExpVerifyFilePath(bootFilePath, MaxBuffer);
  2696. if (!NT_SUCCESS(NtStatus)) {
  2697. goto done;
  2698. }
  2699. //
  2700. // Verify that OsOptions doesn't encroach into FriendlyName, and that
  2701. // FriendlyName doesn't encroach into BootFilePath.
  2702. //
  2703. if (((localBootEntry->OsOptions + localBootEntry->OsOptionsLength) > (PUCHAR)friendlyName) ||
  2704. (((PUCHAR)friendlyName + friendlyNameLength) > (PUCHAR)bootFilePath)) {
  2705. NtStatus = STATUS_INVALID_PARAMETER;
  2706. goto done;
  2707. }
  2708. //
  2709. // The format of the input buffer has been validated. Build the variable value
  2710. // that will be stored in NVRAM. Begin by determining the lengths of the file
  2711. // paths that will be stored. If the caller provided the paths in non-EFI
  2712. // format, they need to be translated.
  2713. //
  2714. if (bootFilePath->Type != FILE_PATH_TYPE_EFI) {
  2715. efiBootFilePathLength = 0;
  2716. NtStatus = ZwTranslateFilePath(bootFilePath,
  2717. FILE_PATH_TYPE_EFI,
  2718. NULL,
  2719. &efiBootFilePathLength);
  2720. if (NtStatus != STATUS_BUFFER_TOO_SMALL) {
  2721. goto done;
  2722. }
  2723. translatedBootFilePath = ExAllocatePoolWithTag(NonPagedPool,
  2724. efiBootFilePathLength,
  2725. 'rvnE');
  2726. if (translatedBootFilePath == NULL) {
  2727. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  2728. goto done;
  2729. }
  2730. RtlZeroMemory(translatedBootFilePath, efiBootFilePathLength);
  2731. length = efiBootFilePathLength;
  2732. NtStatus = ZwTranslateFilePath(bootFilePath,
  2733. FILE_PATH_TYPE_EFI,
  2734. translatedBootFilePath,
  2735. &length);
  2736. if (!NT_SUCCESS(NtStatus)) {
  2737. goto done;
  2738. }
  2739. if (length != efiBootFilePathLength) {
  2740. NtStatus = STATUS_UNSUCCESSFUL;
  2741. }
  2742. } else {
  2743. efiBootFilePathLength = bootFilePath->Length;
  2744. translatedBootFilePath = bootFilePath;
  2745. }
  2746. efiBootFilePathLength = efiBootFilePathLength - FIELD_OFFSET(FILE_PATH, FilePath);
  2747. efiWindowsFilePathLength = 0;
  2748. if (isWindowsOs &&
  2749. (windowsFilePath->Type != FILE_PATH_TYPE_EFI)) {
  2750. NtStatus = ZwTranslateFilePath(windowsFilePath,
  2751. FILE_PATH_TYPE_EFI,
  2752. NULL,
  2753. &efiWindowsFilePathLength);
  2754. if (NtStatus != STATUS_BUFFER_TOO_SMALL) {
  2755. goto done;
  2756. }
  2757. osOptionsLength = localBootEntry->OsOptionsLength -
  2758. windowsFilePath->Length + efiWindowsFilePathLength;
  2759. } else {
  2760. osOptionsLength = localBootEntry->OsOptionsLength;
  2761. }
  2762. //
  2763. // Calculate the length required for the variable value.
  2764. //
  2765. requiredLength = FIELD_OFFSET(EFI_LOAD_OPTION, Description);
  2766. requiredLength += friendlyNameLength;
  2767. requiredLength += efiBootFilePathLength;
  2768. requiredLength += osOptionsLength;
  2769. //
  2770. // Allocate a buffer to hold the variable value.
  2771. //
  2772. efiLoadOption = ExAllocatePoolWithTag(NonPagedPool, requiredLength, 'rvnE');
  2773. if (efiLoadOption == NULL) {
  2774. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  2775. goto done;
  2776. }
  2777. RtlZeroMemory(efiLoadOption, requiredLength);
  2778. //
  2779. // Build the variable value.
  2780. //
  2781. efiLoadOption->Attributes = 0;
  2782. if ((localBootEntry->Attributes & BOOT_ENTRY_ATTRIBUTE_ACTIVE) != 0) {
  2783. efiLoadOption->Attributes = LOAD_OPTION_ACTIVE;
  2784. }
  2785. efiLoadOption->FilePathLength = (USHORT)efiBootFilePathLength;
  2786. memcpy(efiLoadOption->Description, friendlyName, friendlyNameLength);
  2787. efiBootFilePath = (PUCHAR)((PUCHAR)efiLoadOption->Description + friendlyNameLength);
  2788. memcpy(efiBootFilePath, translatedBootFilePath->FilePath, efiBootFilePathLength);
  2789. efiOsOptions = efiBootFilePath + efiBootFilePathLength;
  2790. if (isWindowsOs &&
  2791. (windowsFilePath->Type != FILE_PATH_TYPE_EFI)) {
  2792. PFILE_PATH efiWindowsFilePath;
  2793. memcpy(efiOsOptions, windowsOsOptions, windowsOsOptions->OsLoadPathOffset);
  2794. ((WINDOWS_OS_OPTIONS UNALIGNED *)efiOsOptions)->Length = osOptionsLength;
  2795. efiWindowsFilePath = (PFILE_PATH)(efiOsOptions + windowsOsOptions->OsLoadPathOffset);
  2796. length = efiWindowsFilePathLength;
  2797. NtStatus = ZwTranslateFilePath(windowsFilePath,
  2798. FILE_PATH_TYPE_EFI,
  2799. efiWindowsFilePath,
  2800. &efiWindowsFilePathLength);
  2801. if (NtStatus != STATUS_SUCCESS) {
  2802. goto done;
  2803. }
  2804. if (length != efiWindowsFilePathLength) {
  2805. NtStatus = STATUS_UNSUCCESSFUL;
  2806. }
  2807. } else {
  2808. memcpy(efiOsOptions, localBootEntry->OsOptions, osOptionsLength);
  2809. }
  2810. //
  2811. // If CreateNewEntry is true, then find an unused identifier to assign to
  2812. // this boot entry. If CreateNewEntry is false, then verify that the
  2813. // provided identifier exists.
  2814. //
  2815. KeEnterCriticalRegion();
  2816. ExAcquireFastMutexUnsafe(&ExpEnvironmentLock);
  2817. if (CreateNewEntry) {
  2818. for ( id = 0; id <= MAXUSHORT; id++ ) {
  2819. swprintf( idString, L"Boot%04x", id);
  2820. length = 0;
  2821. NtStatus = HalGetEnvironmentVariableEx(idString,
  2822. &EfiBootVariablesGuid,
  2823. NULL,
  2824. &length,
  2825. NULL);
  2826. if (NtStatus == STATUS_VARIABLE_NOT_FOUND) {
  2827. break;
  2828. }
  2829. if ((NtStatus != STATUS_SUCCESS) && (NtStatus != STATUS_BUFFER_TOO_SMALL)) {
  2830. goto done_unlock;
  2831. }
  2832. }
  2833. if (id > MAXUSHORT) {
  2834. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  2835. goto done_unlock;
  2836. }
  2837. } else {
  2838. id = localBootEntry->Id;
  2839. swprintf( idString, L"Boot%04x", localBootEntry->Id);
  2840. length = 0;
  2841. NtStatus = HalGetEnvironmentVariableEx(idString,
  2842. &EfiBootVariablesGuid,
  2843. NULL,
  2844. &length,
  2845. NULL);
  2846. if ((NtStatus != STATUS_SUCCESS) && (NtStatus != STATUS_BUFFER_TOO_SMALL)) {
  2847. goto done_unlock;
  2848. }
  2849. }
  2850. //
  2851. // Set or update the boot entry environment variable.
  2852. //
  2853. NtStatus = HalSetEnvironmentVariableEx(idString,
  2854. &EfiBootVariablesGuid,
  2855. efiLoadOption,
  2856. requiredLength,
  2857. VARIABLE_ATTRIBUTE_NON_VOLATILE);
  2858. done_unlock:
  2859. ExReleaseFastMutexUnsafe(&ExpEnvironmentLock);
  2860. KeLeaveCriticalRegion();
  2861. done:
  2862. if (efiLoadOption != NULL) {
  2863. ExFreePool(efiLoadOption);
  2864. }
  2865. if ((translatedBootFilePath != NULL) && (translatedBootFilePath != bootFilePath)) {
  2866. ExFreePool(translatedBootFilePath);
  2867. }
  2868. ExFreePool(localBootEntry);
  2869. //
  2870. // Establish an exception handler and attempt to write the return
  2871. // identifier. If the write attempt fails, then return the exception
  2872. // code as the service status.
  2873. //
  2874. try {
  2875. //
  2876. // Write the return identifier.
  2877. //
  2878. if (CreateNewEntry && ARGUMENT_PRESENT(Id) && NT_SUCCESS(NtStatus)) {
  2879. *Id = id;
  2880. }
  2881. return NtStatus;
  2882. //
  2883. // If an exception occurs during the write of the return data, then
  2884. // always handle the exception and return the exception code as the
  2885. // status value.
  2886. //
  2887. } except (EXCEPTION_EXECUTE_HANDLER) {
  2888. return GetExceptionCode();
  2889. }
  2890. #endif // else !defined(EFI_NVRAM_ENABLED)
  2891. } // ExpSetBootEntry
  2892. //
  2893. // The remainder of this module is routines that are only compiled when
  2894. // EFI_NVRAM_ENABLED is defined.
  2895. //
  2896. #if defined(EFI_NVRAM_ENABLED)
  2897. ULONG
  2898. ExpSafeWcslen (
  2899. IN PWSTR String,
  2900. IN PWSTR Max
  2901. )
  2902. {
  2903. PWSTR p = String;
  2904. while ((p < Max) && (*p != 0)) {
  2905. p++;
  2906. }
  2907. if (p < Max) {
  2908. return (ULONG)(p - String);
  2909. }
  2910. return 0xffffffff;
  2911. } // ExpSafeWcslen
  2912. NTSTATUS
  2913. ExpTranslateArcPath (
  2914. IN PFILE_PATH InputPath,
  2915. IN ULONG OutputType,
  2916. OUT PFILE_PATH OutputPath,
  2917. IN OUT PULONG OutputPathLength
  2918. )
  2919. {
  2920. #if 0
  2921. UNREFERENCED_PARAMETER(InputPath);
  2922. UNREFERENCED_PARAMETER(OutputType);
  2923. UNREFERENCED_PARAMETER(OutputPath);
  2924. UNREFERENCED_PARAMETER(OutputPathLength);
  2925. return STATUS_NOT_IMPLEMENTED;
  2926. #endif
  2927. PWSTR deviceName, pathName;
  2928. ULONG deviceNameCount;
  2929. BOOLEAN signatureFormat;
  2930. NTSTATUS status;
  2931. //
  2932. // Possible Arc Path formats
  2933. // signature(<guid/signature>-<part#>-<start>-<size>)[\filePart]
  2934. // signature(<guid>)[\filePart]
  2935. // multi(0)disk(0)fdisk(0)[\filePart]
  2936. // multi(0)disk(0)rdisk(0)[\filePart]
  2937. // multi(0)disk(0)rdisk(0)partition(0)[\filePart]
  2938. //
  2939. //
  2940. // Determine if ArcName has signature() format
  2941. // Parse out DeviceName & FilePart
  2942. //
  2943. status = ExpParseArcPathName (
  2944. (PWSTR)(InputPath->FilePath),
  2945. &deviceName,
  2946. &pathName,
  2947. &deviceNameCount,
  2948. &signatureFormat
  2949. );
  2950. if ( !NT_SUCCESS(status) ) {
  2951. return status;
  2952. }
  2953. //
  2954. // not signature() format
  2955. //
  2956. if( signatureFormat == FALSE ) {
  2957. if( InputPath->Type != FILE_PATH_TYPE_ARC ) {
  2958. return( STATUS_INVALID_PARAMETER );
  2959. }
  2960. status = ExpConvertArcName(
  2961. OutputType,
  2962. OutputPath,
  2963. OutputPathLength,
  2964. deviceName,
  2965. pathName,
  2966. deviceNameCount
  2967. );
  2968. return( status );
  2969. }
  2970. //
  2971. // This arc signature() format should be FILE_PATH_TYPE_ARC_SIGNATURE
  2972. //
  2973. if( InputPath->Type != FILE_PATH_TYPE_ARC_SIGNATURE ) {
  2974. return( STATUS_INVALID_PARAMETER );
  2975. }
  2976. status = ExpConvertSignatureName(
  2977. OutputType,
  2978. OutputPath,
  2979. OutputPathLength,
  2980. deviceName,
  2981. pathName,
  2982. deviceNameCount
  2983. );
  2984. return( status );
  2985. } // ExpTranslateArcPath
  2986. NTSTATUS
  2987. ExpTranslateEfiPath (
  2988. IN PFILE_PATH InputPath,
  2989. IN ULONG OutputType,
  2990. OUT PFILE_PATH OutputPath,
  2991. IN OUT PULONG OutputPathLength
  2992. )
  2993. {
  2994. NTSTATUS status;
  2995. HARDDRIVE_DEVICE_PATH *dpHarddrive = NULL;
  2996. ULONG requiredLength;
  2997. UNICODE_STRING guidString;
  2998. UNICODE_STRING deviceNameString;
  2999. PWSTR linkName, pPathName;
  3000. BOOLEAN GPTpartition;
  3001. ULONG partitionNumber, diskNumber;
  3002. ULONGLONG partitionStart, partitionSize;
  3003. //
  3004. // Find the MEDIA/HARDDRIVE and MEDIA/FILEPATH elements in the device
  3005. // path. Note that although EFI allows multiple device paths to appear
  3006. // in a single device path (as in the PATH variable), we only look at
  3007. // the first one.
  3008. //
  3009. status = ExpParseEfiPath(
  3010. (EFI_DEVICE_PATH *)InputPath->FilePath,
  3011. &dpHarddrive,
  3012. &pPathName,
  3013. &GPTpartition
  3014. );
  3015. if( !NT_SUCCESS( status ) ) {
  3016. return( status );
  3017. }
  3018. //
  3019. // If the target type is ARC_SIGNATURE, then we have all of the
  3020. // information we need. Otherwise, we need to find the NT device
  3021. // with the given signature.
  3022. //
  3023. if ( OutputType == FILE_PATH_TYPE_ARC_SIGNATURE ) {
  3024. partitionNumber = dpHarddrive->PartitionNumber;
  3025. partitionStart = dpHarddrive->PartitionStart;
  3026. partitionSize = dpHarddrive->PartitionSize;
  3027. status = ExpCreateOutputSIGNATURE(
  3028. OutputPath,
  3029. OutputPathLength,
  3030. (PDISK_SIGNATURE_NEW)(dpHarddrive->Signature),
  3031. &(partitionNumber),
  3032. &(partitionStart),
  3033. &(partitionSize),
  3034. pPathName,
  3035. GPTpartition
  3036. );
  3037. if( pPathName != NULL ) {
  3038. ExFreePool( pPathName );
  3039. }
  3040. ExFreePool(dpHarddrive);
  3041. return( status );
  3042. }
  3043. //
  3044. // OutputType is ARC or NT. Find the NT device for this device path.
  3045. // For a GPT partition, this is done by translating the symbolic name
  3046. // \??\Volume{<guid>} which will link to \Device\HarddiskVolume<n>.
  3047. //
  3048. status = STATUS_OBJECT_NAME_NOT_FOUND;
  3049. //
  3050. // Quick path for GPT disk
  3051. // Translate the symbolic link \??\Volume{<guid>}.
  3052. //
  3053. // First, get the GUID in "pretty" format. Then allocate a buffer to hold
  3054. // the full name string and create that string. Then translate the
  3055. // symbolic name.
  3056. //
  3057. // NB: Because the mount manager doesn't create a symbolic link like this
  3058. // for the EFI system partition, this routine cannot be used to
  3059. // translate an EFI device path for the system partition to an NT path.
  3060. //
  3061. if( GPTpartition == TRUE ) {
  3062. status = RtlStringFromGUID( (LPGUID)dpHarddrive->Signature, &guidString );
  3063. if ( !NT_SUCCESS(status) ) {
  3064. if( pPathName != NULL ) {
  3065. ExFreePool( pPathName );
  3066. }
  3067. ExFreePool(dpHarddrive);
  3068. return status;
  3069. }
  3070. #define LINK_NAME_PREFIX L"\\??\\Volume"
  3071. requiredLength = ((ULONG)wcslen( LINK_NAME_PREFIX ) + 1) * sizeof(WCHAR);
  3072. requiredLength += guidString.Length;
  3073. linkName = ExAllocatePoolWithTag( NonPagedPool, requiredLength, 'rvnE' );
  3074. if ( linkName == NULL ) {
  3075. ExFreePool( guidString.Buffer );
  3076. if( pPathName != NULL ) {
  3077. ExFreePool( pPathName );
  3078. }
  3079. ExFreePool(dpHarddrive);
  3080. return STATUS_INSUFFICIENT_RESOURCES;
  3081. }
  3082. wcscpy( linkName, LINK_NAME_PREFIX );
  3083. wcscat( linkName, guidString.Buffer );
  3084. ExFreePool( guidString.Buffer );
  3085. status = ExpTranslateSymbolicLink(
  3086. linkName,
  3087. &deviceNameString
  3088. );
  3089. ExFreePool( linkName );
  3090. }
  3091. //
  3092. // check if the quick path was not taken or no object was found
  3093. //
  3094. if ( !NT_SUCCESS(status) ) {
  3095. //
  3096. // long path, opens all disks in search of the signature
  3097. //
  3098. partitionNumber = dpHarddrive->PartitionNumber;
  3099. status = ExpFindDiskSignature(
  3100. (PDISK_SIGNATURE_NEW)(dpHarddrive->Signature),
  3101. &partitionNumber,
  3102. &diskNumber,
  3103. &partitionStart,
  3104. &partitionSize,
  3105. GPTpartition
  3106. );
  3107. if ( !NT_SUCCESS(status) ) {
  3108. if( pPathName != NULL ) {
  3109. ExFreePool( pPathName );
  3110. }
  3111. ExFreePool(dpHarddrive);
  3112. return status;
  3113. }
  3114. //
  3115. // The user has provided the partition number, start address,
  3116. // and size; so verify the input with the found results.
  3117. //
  3118. if( (dpHarddrive->PartitionNumber != partitionNumber) ||
  3119. (dpHarddrive->PartitionStart != partitionStart) ||
  3120. (dpHarddrive->PartitionSize != partitionSize) ) {
  3121. if( pPathName != NULL ) {
  3122. ExFreePool( pPathName );
  3123. }
  3124. ExFreePool(dpHarddrive);
  3125. return( STATUS_INVALID_PARAMETER );
  3126. }
  3127. //
  3128. // create the NT disk Symbolic link name
  3129. // \Device\Harddisk[diskNumber]\Partition[PartitionNumber]
  3130. //
  3131. #define NT_DISK_NAME_FORMAT L"\\Device\\Harddisk%lu\\Partition%lu"
  3132. #define NT_DISK_NAME_COUNT 47 // 7 + 9 + (10) + 10 + (10) + 1
  3133. linkName = ExAllocatePoolWithTag(
  3134. NonPagedPool,
  3135. ( NT_DISK_NAME_COUNT * sizeof( WCHAR ) ),
  3136. 'rvnE'
  3137. );
  3138. if( linkName == NULL ) {
  3139. if( pPathName != NULL ) {
  3140. ExFreePool( pPathName );
  3141. }
  3142. ExFreePool(dpHarddrive);
  3143. return( STATUS_INSUFFICIENT_RESOURCES );
  3144. }
  3145. _snwprintf(
  3146. linkName,
  3147. NT_DISK_NAME_COUNT,
  3148. NT_DISK_NAME_FORMAT,
  3149. diskNumber,
  3150. partitionNumber
  3151. );
  3152. status = ExpTranslateSymbolicLink(
  3153. linkName,
  3154. &deviceNameString
  3155. );
  3156. ExFreePool( linkName );
  3157. if( !NT_SUCCESS(status) ) {
  3158. if( pPathName != NULL ) {
  3159. ExFreePool( pPathName );
  3160. }
  3161. ExFreePool(dpHarddrive);
  3162. return( status );
  3163. }
  3164. }
  3165. //
  3166. // We now have the NT name of the device. If the target type is NT, then
  3167. // we have all of the information we need.
  3168. //
  3169. if ( OutputType == FILE_PATH_TYPE_NT ) {
  3170. status = ExpCreateOutputNT(
  3171. OutputPath,
  3172. OutputPathLength,
  3173. &deviceNameString,
  3174. pPathName
  3175. );
  3176. ExFreePool( deviceNameString.Buffer );
  3177. if( pPathName != NULL ) {
  3178. ExFreePool( pPathName );
  3179. }
  3180. ExFreePool(dpHarddrive);
  3181. return( status );
  3182. }
  3183. //
  3184. // The output type is ARC.
  3185. //
  3186. status = ExpCreateOutputARC(
  3187. OutputPath,
  3188. OutputPathLength,
  3189. &deviceNameString,
  3190. pPathName
  3191. );
  3192. ExFreePool( deviceNameString.Buffer );
  3193. if( pPathName != NULL ) {
  3194. ExFreePool( pPathName );
  3195. }
  3196. ExFreePool(dpHarddrive);
  3197. return( status );
  3198. } // ExpTranslateEfiPath
  3199. NTSTATUS
  3200. ExpTranslateNtPath (
  3201. IN PFILE_PATH InputPath,
  3202. IN ULONG OutputType,
  3203. OUT PFILE_PATH OutputPath,
  3204. IN OUT PULONG OutputPathLength
  3205. )
  3206. {
  3207. NTSTATUS status;
  3208. UNICODE_STRING string, deviceNameString;
  3209. OBJECT_ATTRIBUTES obja;
  3210. IO_STATUS_BLOCK iosb;
  3211. HANDLE handle;
  3212. PARTITION_INFORMATION_EX partitionInfo;
  3213. PDRIVE_LAYOUT_INFORMATION_EX driveLayoutInfo = NULL;
  3214. ULONG driveLayoutLength;
  3215. PWSTR deviceName, pathName;
  3216. ULONG pathNameLength;
  3217. ULONG signatureMBR = 0;
  3218. PDISK_SIGNATURE_NEW pDiskSignature;
  3219. BOOLEAN TranslatedSymLink = TRUE;
  3220. BOOLEAN GPTpartition;
  3221. deviceName = (PWSTR)InputPath->FilePath;
  3222. RtlInitUnicodeString( &string, deviceName );
  3223. pathName = (PWSTR)((PUCHAR)deviceName + string.Length + sizeof(WCHAR));
  3224. pathNameLength = (ULONG)wcslen(pathName);
  3225. if (pathNameLength == 0) {
  3226. pathName = NULL;
  3227. }
  3228. //
  3229. // For output type Arc,
  3230. // attempt drill down NT name
  3231. // if NT object exists
  3232. // match with symlink in \ArcName
  3233. //
  3234. if (OutputType == FILE_PATH_TYPE_ARC) {
  3235. status = ExpTranslateSymbolicLink(
  3236. deviceName,
  3237. &deviceNameString
  3238. );
  3239. if (!NT_SUCCESS(status)) {
  3240. //
  3241. // If non-symlink NT name exists as an object in the NT namespace,
  3242. // then the return code will be STATUS_OBJECT_TYPE_MISMATCH
  3243. // else the return code will be STATUS_OBJECT_NAME_NOT_FOUND
  3244. //
  3245. if (status != STATUS_OBJECT_TYPE_MISMATCH) {
  3246. return( status );
  3247. }
  3248. deviceNameString.Buffer = string.Buffer;
  3249. deviceNameString.Length = string.Length;
  3250. deviceNameString.MaximumLength = string.MaximumLength;
  3251. TranslatedSymLink = FALSE;
  3252. }
  3253. status = ExpCreateOutputARC(
  3254. OutputPath,
  3255. OutputPathLength,
  3256. &deviceNameString,
  3257. pathName
  3258. );
  3259. if (TranslatedSymLink == TRUE) {
  3260. ExFreePool( deviceNameString.Buffer );
  3261. }
  3262. return( status );
  3263. }
  3264. //
  3265. // Open the target partition and get its partition information.
  3266. //
  3267. InitializeObjectAttributes(
  3268. &obja,
  3269. &string,
  3270. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  3271. NULL,
  3272. NULL
  3273. );
  3274. status = ZwOpenFile(
  3275. &handle,
  3276. FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  3277. &obja,
  3278. &iosb,
  3279. FILE_SHARE_READ | FILE_SHARE_WRITE,
  3280. FILE_NON_DIRECTORY_FILE
  3281. );
  3282. if (!NT_SUCCESS(status)) {
  3283. return status;
  3284. }
  3285. status = ZwDeviceIoControlFile(
  3286. handle,
  3287. NULL,
  3288. NULL,
  3289. NULL,
  3290. &iosb,
  3291. IOCTL_DISK_GET_PARTITION_INFO_EX,
  3292. NULL,
  3293. 0,
  3294. &partitionInfo,
  3295. sizeof(partitionInfo)
  3296. );
  3297. if (!NT_SUCCESS(status)) {
  3298. ZwClose(handle);
  3299. return status;
  3300. }
  3301. if ((partitionInfo.PartitionStyle != PARTITION_STYLE_MBR) &&
  3302. (partitionInfo.PartitionStyle != PARTITION_STYLE_GPT)) {
  3303. ZwClose(handle);
  3304. return STATUS_UNRECOGNIZED_MEDIA;
  3305. }
  3306. if (partitionInfo.PartitionStyle == PARTITION_STYLE_MBR) {
  3307. driveLayoutLength = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry) +
  3308. (sizeof(PARTITION_INFORMATION_EX) * 16);
  3309. while (TRUE) {
  3310. driveLayoutInfo = ExAllocatePoolWithTag(NonPagedPool, driveLayoutLength, 'rvnE');
  3311. if (driveLayoutInfo == NULL ) {
  3312. ZwClose(handle);
  3313. return STATUS_INSUFFICIENT_RESOURCES;
  3314. }
  3315. status = ZwDeviceIoControlFile(
  3316. handle,
  3317. NULL,
  3318. NULL,
  3319. NULL,
  3320. &iosb,
  3321. IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
  3322. NULL,
  3323. 0,
  3324. driveLayoutInfo,
  3325. driveLayoutLength
  3326. );
  3327. if (NT_SUCCESS(status)) {
  3328. break;
  3329. }
  3330. ExFreePool(driveLayoutInfo);
  3331. if (status == STATUS_BUFFER_TOO_SMALL) {
  3332. driveLayoutLength *= 2;
  3333. continue;
  3334. }
  3335. ZwClose(handle);
  3336. return status;
  3337. }
  3338. if (NT_SUCCESS(status)) {
  3339. signatureMBR = driveLayoutInfo->Mbr.Signature;
  3340. ExFreePool(driveLayoutInfo);
  3341. }
  3342. }
  3343. ZwClose(handle);
  3344. if (partitionInfo.PartitionStyle == PARTITION_STYLE_GPT) {
  3345. pDiskSignature = (PDISK_SIGNATURE_NEW)(&(partitionInfo.Gpt.PartitionId));
  3346. GPTpartition = TRUE;
  3347. } else {
  3348. pDiskSignature = (PDISK_SIGNATURE_NEW)(&signatureMBR);
  3349. GPTpartition = FALSE;
  3350. }
  3351. if (OutputType == FILE_PATH_TYPE_EFI) {
  3352. status = ExpCreateOutputEFI(
  3353. OutputPath,
  3354. OutputPathLength,
  3355. pDiskSignature,
  3356. &(partitionInfo.PartitionNumber),
  3357. (PULONGLONG)(&(partitionInfo.StartingOffset.QuadPart)),
  3358. (PULONGLONG)(&(partitionInfo.PartitionLength.QuadPart)),
  3359. pathName,
  3360. GPTpartition
  3361. );
  3362. return( status );
  3363. }
  3364. //
  3365. // OutputType is ARC_SIGNATURE
  3366. //
  3367. status = ExpCreateOutputSIGNATURE(
  3368. OutputPath,
  3369. OutputPathLength,
  3370. pDiskSignature,
  3371. &(partitionInfo.PartitionNumber),
  3372. (PULONGLONG)(&(partitionInfo.StartingOffset.QuadPart)),
  3373. (PULONGLONG)(&(partitionInfo.PartitionLength.QuadPart)),
  3374. pathName,
  3375. GPTpartition
  3376. );
  3377. return( status );
  3378. } // ExpTranslateNtPath
  3379. LOGICAL
  3380. ExpTranslateBootEntryNameToId (
  3381. IN PWSTR Name,
  3382. OUT PULONG Id
  3383. )
  3384. {
  3385. ULONG number;
  3386. ULONG i;
  3387. WCHAR c;
  3388. if ((towlower(Name[0]) != 'b') ||
  3389. (towlower(Name[1]) != 'o') ||
  3390. (towlower(Name[2]) != 'o') ||
  3391. (towlower(Name[3]) != 't') ) {
  3392. return FALSE;
  3393. }
  3394. number = 0;
  3395. for (i = 4; i < 8; i++) {
  3396. c = towlower(Name[i]);
  3397. if ((c >= L'0') && (c <= L'9')) {
  3398. number = (number * 16) + (c - L'0');
  3399. } else if ((c >= L'a') && (c <= L'f')) {
  3400. number = (number * 16) + (c - L'a' + 10);
  3401. } else {
  3402. return FALSE;
  3403. }
  3404. }
  3405. if (Name[8] != 0) {
  3406. return FALSE;
  3407. }
  3408. *Id = number;
  3409. return TRUE;
  3410. } // ExpTranslateBootEntryNameToId
  3411. NTSTATUS
  3412. ExpTranslateSymbolicLink (
  3413. IN PWSTR LinkName,
  3414. OUT PUNICODE_STRING ResultName
  3415. )
  3416. /*++
  3417. Routine Description:
  3418. This routine translates the input symbolic link name by drilling down
  3419. through symbolic links until it finds an object that is not a link.
  3420. Arguments:
  3421. LinkName - Supplies the name of the link at which to start translating.
  3422. ResultName - Supplies the address of a UNICODE_STRING descriptor that
  3423. will receive the result name. The storage for the result name is
  3424. allocated from nonpaged pool using ExAllocatePool.
  3425. Return Value:
  3426. STATUS_SUCCESS is returned if the input name was a symbolic link and
  3427. all translations completely successfully.
  3428. Failure codes will be returned if the input name was not a link, if
  3429. translations failed, or if allocation of the output buffer failed.
  3430. --*/
  3431. {
  3432. NTSTATUS status;
  3433. UNICODE_STRING linkString;
  3434. UNICODE_STRING resultString;
  3435. PWSTR resultBuffer;
  3436. ULONG resultBufferLength;
  3437. ULONG requiredLength;
  3438. OBJECT_ATTRIBUTES objectAttributes;
  3439. HANDLE handle;
  3440. resultBuffer = NULL;
  3441. resultBufferLength = sizeof(WCHAR);
  3442. //
  3443. // Open the input link.
  3444. //
  3445. RtlInitUnicodeString( &linkString, LinkName );
  3446. InitializeObjectAttributes(
  3447. &objectAttributes,
  3448. &linkString,
  3449. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  3450. NULL,
  3451. NULL
  3452. );
  3453. status = ZwOpenSymbolicLinkObject(
  3454. &handle,
  3455. (ACCESS_MASK)SYMBOLIC_LINK_QUERY,
  3456. &objectAttributes
  3457. );
  3458. if ( !NT_SUCCESS(status) ) {
  3459. return status;
  3460. }
  3461. while ( TRUE ) {
  3462. while ( TRUE ) {
  3463. //
  3464. // Get the translation for this link, allocating more
  3465. // space as needed.
  3466. //
  3467. resultString.Length = 0;
  3468. resultString.MaximumLength = (USHORT)(resultBufferLength - sizeof(WCHAR));
  3469. resultString.Buffer = resultBuffer;
  3470. status = ZwQuerySymbolicLinkObject(
  3471. handle,
  3472. &resultString,
  3473. &requiredLength
  3474. );
  3475. if ( status != STATUS_BUFFER_TOO_SMALL ) {
  3476. break;
  3477. }
  3478. //
  3479. // The buffer was too small. Reallocate it, allowing room for a
  3480. // null terminator, which might not be present in the translation,
  3481. // and try again.
  3482. //
  3483. if ( resultBuffer != NULL ) {
  3484. ExFreePool( resultBuffer );
  3485. }
  3486. resultBufferLength = requiredLength + sizeof(WCHAR);
  3487. resultBuffer = ExAllocatePoolWithTag( NonPagedPool, resultBufferLength, 'rvnE' );
  3488. if ( resultBuffer == NULL ) {
  3489. ZwClose( handle );
  3490. return STATUS_INSUFFICIENT_RESOURCES;
  3491. }
  3492. }
  3493. //
  3494. // Translation done. Close the link. If translation failed, return
  3495. // the failure status.
  3496. //
  3497. ZwClose( handle );
  3498. if (!NT_SUCCESS(status)) {
  3499. if ( resultBuffer != NULL) {
  3500. ExFreePool( resultBuffer );
  3501. }
  3502. return status;
  3503. }
  3504. //
  3505. // Terminate the result string, in case it wasn't already terminated.
  3506. //
  3507. resultBuffer[resultString.Length / sizeof(WCHAR)] = UNICODE_NULL;
  3508. resultString.MaximumLength = (USHORT)(resultBufferLength);
  3509. //
  3510. // See if the result name is also a symbolic name. Try to open it
  3511. // as a link. If this fails, then break out of the loop and return
  3512. // this name as the result.
  3513. //
  3514. RtlInitUnicodeString( &linkString, resultBuffer );
  3515. InitializeObjectAttributes(
  3516. &objectAttributes,
  3517. &linkString,
  3518. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  3519. NULL,
  3520. NULL
  3521. );
  3522. status = ZwOpenSymbolicLinkObject(
  3523. &handle,
  3524. (ACCESS_MASK)SYMBOLIC_LINK_QUERY,
  3525. &objectAttributes
  3526. );
  3527. if ( !NT_SUCCESS(status) ) {
  3528. break;
  3529. }
  3530. //
  3531. // This name is also a symbolic link. Loop back and translate it.
  3532. //
  3533. }
  3534. //
  3535. // Set up the return string to point to the final result.
  3536. //
  3537. *ResultName = resultString;
  3538. return STATUS_SUCCESS;
  3539. } // ExpTranslateSymbolicLink
  3540. LOGICAL
  3541. ExpIsDevicePathForRemovableMedia (
  3542. EFI_DEVICE_PATH *DevicePath
  3543. )
  3544. /*++
  3545. Routine Description:
  3546. This routine determines whether an EFI device path represents a non-file
  3547. specific pointer to a removable media device. It make this determination
  3548. based on finding a HARDWARE/VENDOR device path element, and NOT finding
  3549. MEDIA/HARDDRIVE and MEDIA/FILEPATH elements. When the EFI boot manager
  3550. boot such a device path, it looks in a default location for the file to
  3551. be loaded (\EFI\BOOT\BOOT<arch>.EFI).
  3552. We want to identify these removable media device paths because we do not
  3553. want to put our NT boot entries ahead of removable media entries in the
  3554. boot order, if those removable media entries are at the front of the list.
  3555. This allows an x86-like boot order to be set up: floppy first, then CD,
  3556. then NT boot entries.
  3557. Arguments:
  3558. DevicePath - Supplies the device path to be checked.
  3559. Return Value:
  3560. TRUE is returned if the device path has a HARDWARE/VENDOR element, AND
  3561. that element has the UNKNOWN_DEVICE_GUID, AND the device path does
  3562. NOT have a MEDIA/HARDDRIVE element, AND the device path does NOT
  3563. have a MEDIA/FILEPATH element.
  3564. --*/
  3565. {
  3566. EFI_DEVICE_PATH *dp = DevicePath;
  3567. VENDOR_DEVICE_PATH UNALIGNED *vdp;
  3568. VENDOR_DEVICE_PATH UNALIGNED *vendorDp = NULL;
  3569. HARDDRIVE_DEVICE_PATH UNALIGNED *harddriveDp = NULL;
  3570. FILEPATH_DEVICE_PATH UNALIGNED *filepathDp = NULL;
  3571. //
  3572. // Walk the device path, looking for elements that we care about.
  3573. //
  3574. while (TRUE) {
  3575. if (IsDevicePathEndType(dp)) {
  3576. break;
  3577. }
  3578. if (DevicePathType(dp) == HARDWARE_DEVICE_PATH) {
  3579. if (DevicePathSubType(dp) == HW_VENDOR_DP) {
  3580. //
  3581. // Found a HARDWARE/VENDOR element. If it has the
  3582. // UNKNOWN_DEVICE_GUID, remember that we found it.
  3583. //
  3584. vdp = (VENDOR_DEVICE_PATH UNALIGNED *)dp;
  3585. if ( memcmp( &vdp->Guid, &ExpUnknownDeviceGuid, 16 ) == 0 ) {
  3586. vendorDp = vdp;
  3587. }
  3588. }
  3589. } else if (DevicePathType(dp) == MEDIA_DEVICE_PATH) {
  3590. if (DevicePathSubType(dp) == MEDIA_HARDDRIVE_DP) {
  3591. //
  3592. // Found a MEDIA/HARDDRIVE element. Remember it.
  3593. //
  3594. harddriveDp = (HARDDRIVE_DEVICE_PATH *)dp;
  3595. } else if (DevicePathSubType(dp) == MEDIA_FILEPATH_DP) {
  3596. //
  3597. // Found a MEDIA/FILEPATH element. Remember it.
  3598. //
  3599. filepathDp = (FILEPATH_DEVICE_PATH *)dp;
  3600. }
  3601. }
  3602. dp = NextDevicePathNode(dp);
  3603. }
  3604. //
  3605. // If we didn't find a HARDWARE/VENDOR element, or if we did find either
  3606. // a MEDIA/HARDDRIVE element or a MEDIA/FILEPATH element, then this is
  3607. // not a removable media device path.
  3608. //
  3609. if ((vendorDp == NULL) || (harddriveDp != NULL) || (filepathDp != NULL)) {
  3610. return FALSE;
  3611. }
  3612. return TRUE;
  3613. } // ExpIsDevicePathForRemovableMedia
  3614. NTSTATUS
  3615. ExpVerifyFilePath (
  3616. PFILE_PATH FilePath,
  3617. PUCHAR Max
  3618. )
  3619. {
  3620. EFI_DEVICE_PATH *dp;
  3621. PUCHAR dpMax;
  3622. ULONG length;
  3623. PWSTR p;
  3624. if (((PUCHAR)FilePath > Max) ||
  3625. (((PUCHAR)FilePath + FIELD_OFFSET(FILE_PATH, FilePath)) > Max) ||
  3626. (FilePath->Length < FIELD_OFFSET(FILE_PATH, FilePath)) ||
  3627. (((PUCHAR)FilePath + FilePath->Length) < (PUCHAR)FilePath) ||
  3628. (((PUCHAR)FilePath + FilePath->Length) > Max) ||
  3629. (FilePath->Version == 0) ||
  3630. (FilePath->Version > FILE_PATH_VERSION) ||
  3631. (FilePath->Type < FILE_PATH_TYPE_MIN) ||
  3632. (FilePath->Type > FILE_PATH_TYPE_MAX)) {
  3633. //DbgPrint( "ExpVerifyFilePath: file path invalid\n" );
  3634. return STATUS_INVALID_PARAMETER;
  3635. }
  3636. switch (FilePath->Type) {
  3637. case FILE_PATH_TYPE_ARC:
  3638. case FILE_PATH_TYPE_ARC_SIGNATURE:
  3639. if (ExpSafeWcslen((PWCHAR)FilePath->FilePath, (PWCHAR)Max) == 0xffffffff) {
  3640. //DbgPrint( "ExpVerifyFilePath: ARC string overruns buffer end\n" );
  3641. return STATUS_INVALID_PARAMETER;
  3642. }
  3643. break;
  3644. case FILE_PATH_TYPE_NT:
  3645. p = (PWSTR)FilePath->FilePath;
  3646. length = ExpSafeWcslen(p, (PWCHAR)Max);
  3647. if (length != 0xffffffff) {
  3648. p = p + length + 1;
  3649. length = ExpSafeWcslen(p, (PWCHAR)Max);
  3650. }
  3651. if (length == 0xffffffff) {
  3652. //DbgPrint( "ExpVerifyFilePath: NT string overruns buffer end\n" );
  3653. return STATUS_INVALID_PARAMETER;
  3654. }
  3655. break;
  3656. case FILE_PATH_TYPE_EFI:
  3657. dp = (EFI_DEVICE_PATH *)FilePath->FilePath;
  3658. while (TRUE) {
  3659. if (((PUCHAR)dp + sizeof(EFI_DEVICE_PATH)) > Max) {
  3660. //DbgPrint( "ExpVerifyFilePath: EFI device path overruns buffer end\n" );
  3661. return STATUS_INVALID_PARAMETER;
  3662. }
  3663. length = DevicePathNodeLength(dp);
  3664. if (((PUCHAR)dp + length) > Max) {
  3665. //DbgPrint( "ExpVerifyFilePath: EFI device path overruns buffer end\n" );
  3666. return STATUS_INVALID_PARAMETER;
  3667. }
  3668. dpMax = (PUCHAR)dp + length;
  3669. if (IsDevicePathEndType(dp)) {
  3670. break;
  3671. }
  3672. if ((DevicePathType(dp) == MEDIA_DEVICE_PATH) &&
  3673. (DevicePathSubType(dp) == MEDIA_FILEPATH_DP)) {
  3674. FILEPATH_DEVICE_PATH *fp = (FILEPATH_DEVICE_PATH *)dp;
  3675. if (ExpSafeWcslen(fp->PathName, (PWCHAR)dpMax) == 0xffffffff) {
  3676. //DbgPrint( "ExpVerifyFilePath: EFI filepath string overruns buffer end\n" );
  3677. return STATUS_INVALID_PARAMETER;
  3678. }
  3679. }
  3680. dp = NextDevicePathNode(dp);
  3681. }
  3682. break;
  3683. default:
  3684. ASSERT(FALSE);
  3685. return STATUS_INVALID_PARAMETER;
  3686. }
  3687. return STATUS_SUCCESS;
  3688. } // ExpVerifyFilePath
  3689. NTSTATUS
  3690. ExpVerifyWindowsOsOptions (
  3691. PWINDOWS_OS_OPTIONS WindowsOsOptions,
  3692. ULONG Length
  3693. )
  3694. {
  3695. PUCHAR Max = (PUCHAR)WindowsOsOptions + Length;
  3696. ULONG loadOptionsLength = ExpSafeWcslen(WindowsOsOptions->OsLoadOptions, (PWSTR)Max);
  3697. PFILE_PATH windowsFilePath;
  3698. if ((WindowsOsOptions->Length < FIELD_OFFSET(WINDOWS_OS_OPTIONS, OsLoadOptions)) ||
  3699. (WindowsOsOptions->Length > Length) ||
  3700. (WindowsOsOptions->Version == 0) ||
  3701. (WindowsOsOptions->Version > WINDOWS_OS_OPTIONS_VERSION) ||
  3702. ((WindowsOsOptions->OsLoadPathOffset & (sizeof(ULONG) - 1)) != 0) ||
  3703. (WindowsOsOptions->OsLoadPathOffset >= Length) ||
  3704. (loadOptionsLength == 0xffffffff) ||
  3705. ((PUCHAR)(WindowsOsOptions->OsLoadOptions + loadOptionsLength + 1) >
  3706. (PUCHAR)ADD_OFFSET(WindowsOsOptions, OsLoadPathOffset))) {
  3707. return STATUS_INVALID_PARAMETER;
  3708. }
  3709. windowsFilePath = ADD_OFFSET(WindowsOsOptions, OsLoadPathOffset);
  3710. return ExpVerifyFilePath(windowsFilePath, Max);
  3711. } // ExpVerifyWindowsOsOptions
  3712. NTSTATUS
  3713. ExpParseArcPathName (
  3714. IN PWSTR ArcName,
  3715. OUT PWSTR *ppDeviceName,
  3716. OUT PWSTR *ppPathName,
  3717. OUT PULONG pDeviceNameCount,
  3718. OUT PBOOLEAN pSignatureFormat
  3719. )
  3720. {
  3721. #define SIGNATURE_PREFIX L"signature("
  3722. #define SIGNATURE_PREFIX_COUNT 10
  3723. #define BUFFER_COUNT (SIGNATURE_PREFIX_COUNT + 1)
  3724. PWSTR CurrentName, pathName = NULL;
  3725. WCHAR signaturePrefix[ BUFFER_COUNT ];
  3726. ULONG i;
  3727. BOOLEAN SigFormat = FALSE, PrefixFound = TRUE;
  3728. if( ArcName == NULL ) {
  3729. return( STATUS_INVALID_PARAMETER );
  3730. }
  3731. wcscpy( signaturePrefix, SIGNATURE_PREFIX );
  3732. //
  3733. // check if the ArcName has a signature() format
  3734. //
  3735. for( i = 0; i < SIGNATURE_PREFIX_COUNT; i++ ) {
  3736. if( towlower(ArcName[ i ]) != signaturePrefix[ i ] ) {
  3737. PrefixFound = FALSE;
  3738. break;
  3739. }
  3740. }
  3741. CurrentName = ArcName;
  3742. if( PrefixFound == TRUE ) {
  3743. CurrentName += SIGNATURE_PREFIX_COUNT;
  3744. }
  3745. i = 0;
  3746. while( CurrentName[ i ] != UNICODE_NULL ) {
  3747. //
  3748. // Check if FilePathName has been reached
  3749. //
  3750. if( CurrentName[ i ] == '\\' ) {
  3751. pathName = CurrentName;
  3752. pathName += i;
  3753. break;
  3754. }
  3755. if( (PrefixFound == TRUE) && (CurrentName[ i ] == ')') ) {
  3756. SigFormat = TRUE;
  3757. PrefixFound = FALSE; // set to FALSE, to stop checking
  3758. //
  3759. // the FilePathName or UNICODE_NULL must follow
  3760. //
  3761. if( (CurrentName[ i + 1 ] != '\\') &&
  3762. (CurrentName[ i + 1 ] != UNICODE_NULL) ) {
  3763. return( STATUS_INVALID_PARAMETER );
  3764. }
  3765. }
  3766. i++;
  3767. }
  3768. //
  3769. // if PrefixFound is still set
  3770. // the corresponding ')' was not found
  3771. // if i == 0
  3772. // DeviceName does not exist
  3773. //
  3774. if( (PrefixFound == TRUE) || (i == 0) ) {
  3775. return( STATUS_INVALID_PARAMETER );
  3776. }
  3777. *ppDeviceName = CurrentName;
  3778. *ppPathName = pathName;
  3779. *pDeviceNameCount = i;
  3780. *pSignatureFormat = SigFormat;
  3781. return( STATUS_SUCCESS );
  3782. } // ExpParseArcPathName
  3783. NTSTATUS
  3784. ExpParseSignatureName (
  3785. IN PWSTR deviceName,
  3786. IN ULONG deviceNameCount,
  3787. OUT PDISK_SIGNATURE_NEW diskSignature,
  3788. OUT PULONG partitionNumber,
  3789. OUT PULONGLONG partitionStart,
  3790. OUT PULONGLONG partitionSize,
  3791. OUT PBOOLEAN GPTpartition,
  3792. OUT PBOOLEAN longSignature
  3793. )
  3794. {
  3795. UNICODE_STRING bufferString;
  3796. ULONG i, prevI, chCount;
  3797. PWSTR numberString, currentName;
  3798. BOOLEAN foundGUID = FALSE, prettyGUID = FALSE;
  3799. BOOLEAN longSigFound = FALSE;
  3800. NTSTATUS status;
  3801. //
  3802. // Possible formats
  3803. //
  3804. if( deviceName[ 0 ] == '{' ) {
  3805. foundGUID = TRUE;
  3806. }
  3807. //
  3808. // parse the GUID or signature
  3809. //
  3810. i = 0;
  3811. while( i < deviceNameCount ) {
  3812. if( deviceName[ i ] == ')' ) {
  3813. break;
  3814. }
  3815. if( foundGUID == TRUE ) {
  3816. if( deviceName[ i ] == '}' ) {
  3817. prettyGUID = TRUE;
  3818. break;
  3819. }
  3820. }
  3821. else {
  3822. if( deviceName[ i ] == '-' ) {
  3823. break;
  3824. }
  3825. }
  3826. i++;
  3827. }
  3828. //
  3829. // Verify that pretty GUID format has a '}'
  3830. // {33221100-5544-7766-8899-aabbccddeeff}
  3831. //
  3832. if( (foundGUID == TRUE) && (prettyGUID == FALSE) ) {
  3833. return( STATUS_INVALID_PARAMETER );
  3834. }
  3835. #define MBR_SIGNATURE_COUNT 8
  3836. if( i > MBR_SIGNATURE_COUNT ) {
  3837. foundGUID = TRUE;
  3838. }
  3839. if( (foundGUID == TRUE) && (prettyGUID == TRUE) ) {
  3840. //
  3841. // pretty GUID format
  3842. // {33221100-5544-7766-8899-aabbccddeeff}
  3843. //
  3844. bufferString.Buffer = deviceName;
  3845. //
  3846. // (+ 1) for the '}' to be included in the string
  3847. //
  3848. i++;
  3849. bufferString.Length = (USHORT)(i * sizeof(WCHAR));
  3850. bufferString.MaximumLength = bufferString.Length;
  3851. status = RtlGUIDFromString(
  3852. &bufferString,
  3853. &(diskSignature->Guid)
  3854. );
  3855. if( !NT_SUCCESS(status) ) {
  3856. return status;
  3857. }
  3858. }
  3859. else {
  3860. numberString = ExAllocatePoolWithTag(
  3861. NonPagedPool,
  3862. (i + 1) * sizeof(WCHAR),
  3863. 'rvnE'
  3864. );
  3865. if ( numberString == NULL ) {
  3866. return STATUS_INSUFFICIENT_RESOURCES;
  3867. }
  3868. wcsncpy( numberString, deviceName, i );
  3869. numberString[ i ] = UNICODE_NULL;
  3870. if( foundGUID == FALSE ) {
  3871. //
  3872. // MBR Signature format
  3873. // 8459abcc
  3874. //
  3875. status = ExpTranslateHexStringToULONG(
  3876. numberString,
  3877. &(diskSignature->Signature)
  3878. );
  3879. }
  3880. else {
  3881. //
  3882. // ordinary GUID format
  3883. // 00112233445566778899aabbccddeeff
  3884. //
  3885. status = ExpTranslateHexStringToGUID (
  3886. numberString,
  3887. &(diskSignature->Guid)
  3888. );
  3889. }
  3890. ExFreePool( numberString );
  3891. if( !NT_SUCCESS(status) ) {
  3892. return status;
  3893. }
  3894. }
  3895. //
  3896. // check if there is more information in the signature name
  3897. //
  3898. if( (i < deviceNameCount) && (deviceName[ i ] == '-') ) {
  3899. longSigFound = TRUE;
  3900. i++;
  3901. //
  3902. // need to parse <part#>-<start>-<size>)
  3903. // <part#> - 8 hex digits representing the ULONG partition number.
  3904. // (Formatted using %08x.)
  3905. // <start> - 16 hex digits representing the ULONGLONG starting LBA.
  3906. // (Formatted using %016I64x.)
  3907. // <size> - 16 hex digits representing the ULONGLONG partition size.
  3908. // (Formatted using %016I64x.)
  3909. //
  3910. if( i >= deviceNameCount ) {
  3911. return( STATUS_INVALID_PARAMETER );
  3912. }
  3913. #define ULONG_COUNT 8
  3914. #define ULONGLONG_COUNT 16
  3915. //
  3916. // Allocate a buffer to hold a ULONGLONG
  3917. //
  3918. numberString = ExAllocatePoolWithTag(
  3919. NonPagedPool,
  3920. (ULONGLONG_COUNT + 1) * sizeof(WCHAR),
  3921. 'rvnE'
  3922. );
  3923. if ( numberString == NULL ) {
  3924. return STATUS_INSUFFICIENT_RESOURCES;
  3925. }
  3926. prevI = i;
  3927. currentName = deviceName;
  3928. currentName += i;
  3929. while( i < deviceNameCount ) {
  3930. if( deviceName[ i ] == '-' ) {
  3931. break;
  3932. }
  3933. i++;
  3934. }
  3935. chCount = i - prevI;
  3936. if( (chCount == 0) || (chCount > ULONG_COUNT) ) {
  3937. ExFreePool( numberString );
  3938. return( STATUS_INVALID_PARAMETER );
  3939. }
  3940. wcsncpy( numberString, currentName, chCount );
  3941. numberString[ chCount ] = UNICODE_NULL;
  3942. status = ExpTranslateHexStringToULONG( numberString, partitionNumber );
  3943. if( !NT_SUCCESS(status) ) {
  3944. ExFreePool( numberString );
  3945. return status;
  3946. }
  3947. //
  3948. // get the partition start
  3949. //
  3950. i++;
  3951. if( i >= deviceNameCount ) {
  3952. ExFreePool( numberString );
  3953. return( STATUS_INVALID_PARAMETER );
  3954. }
  3955. prevI = i;
  3956. currentName = deviceName;
  3957. currentName += i;
  3958. while( i < deviceNameCount ) {
  3959. if( deviceName[ i ] == '-' ) {
  3960. break;
  3961. }
  3962. i++;
  3963. }
  3964. chCount = i - prevI;
  3965. if( (chCount == 0) || (chCount > ULONGLONG_COUNT) ) {
  3966. ExFreePool( numberString );
  3967. return( STATUS_INVALID_PARAMETER );
  3968. }
  3969. wcsncpy( numberString, currentName, chCount );
  3970. numberString[ chCount ] = UNICODE_NULL;
  3971. status = ExpTranslateHexStringToULONGLONG( numberString, partitionStart );
  3972. if( !NT_SUCCESS(status) ) {
  3973. ExFreePool( numberString );
  3974. return status;
  3975. }
  3976. //
  3977. // get the partition size
  3978. //
  3979. i++;
  3980. if( i >= deviceNameCount ) {
  3981. ExFreePool( numberString );
  3982. return( STATUS_INVALID_PARAMETER );
  3983. }
  3984. prevI = i;
  3985. currentName = deviceName;
  3986. currentName += i;
  3987. while( i < deviceNameCount ) {
  3988. if( deviceName[ i ] == ')' ) { // should be a ')' delimiter
  3989. break;
  3990. }
  3991. i++;
  3992. }
  3993. chCount = i - prevI;
  3994. if( (chCount == 0) || (chCount > ULONGLONG_COUNT) ) {
  3995. ExFreePool( numberString );
  3996. return( STATUS_INVALID_PARAMETER );
  3997. }
  3998. wcsncpy( numberString, currentName, chCount );
  3999. numberString[ chCount ] = UNICODE_NULL;
  4000. status = ExpTranslateHexStringToULONGLONG( numberString, partitionSize );
  4001. ExFreePool( numberString );
  4002. if( !NT_SUCCESS(status) ) {
  4003. return status;
  4004. }
  4005. }
  4006. //
  4007. // At this point,
  4008. // current positition should not pass the last char. of the buffer
  4009. // current positition should be a ')'
  4010. // MBR signature must have the long signature() format (need partition number)
  4011. //
  4012. if( (i >= deviceNameCount) ||
  4013. (deviceName[ i ] != ')') ||
  4014. ((foundGUID == FALSE) && (longSigFound == FALSE)) ) {
  4015. return( STATUS_INVALID_PARAMETER );
  4016. }
  4017. *GPTpartition = foundGUID;
  4018. *longSignature = longSigFound;
  4019. return( STATUS_SUCCESS );
  4020. } // ExpParseSignatureName
  4021. NTSTATUS
  4022. ExpParseEfiPath(
  4023. IN EFI_DEVICE_PATH *pDevicePath,
  4024. OUT HARDDRIVE_DEVICE_PATH **ppHardDriveDP,
  4025. OUT PWSTR *ppPathName,
  4026. OUT PBOOLEAN GPTpartition
  4027. )
  4028. /*++
  4029. Routine Description:
  4030. Parse the EFI_DEVICE_PATH into the HARDDRIVE node and
  4031. entire PathName from the FILEPATH nodes
  4032. Assumptions:
  4033. - Parsing will stop at the first END_DEVICE_PATH node
  4034. - The node graph of the Device path should be
  4035. [~(HARDDRIVE, END_DEVICE_PATH)]* -> [HARDRIVE] -> [FILEPATH]* -> [END_DEVICE_PATH]
  4036. Arguments:
  4037. pDevicePath - Receives an EFI_DEVICE_PATH
  4038. ppHardDriveDP - Will receive a pointer to the
  4039. HARDDRIVE_DEVICE_PATH node
  4040. ppPathName - Will receive a pointer to the
  4041. entire PathName from all the FILEPATH_DEVICE_PATH
  4042. NULL - if the FILEPATH_DEVICE_PATH node does not exist
  4043. GPTpartition - Will receive the type of partition
  4044. TRUE - GPT partition
  4045. FALSE - MBR partition
  4046. Return Value:
  4047. An appropriate status value.
  4048. --*/
  4049. {
  4050. EFI_DEVICE_PATH *pDevPath;
  4051. HARDDRIVE_DEVICE_PATH UNALIGNED *pHD_DP = NULL;
  4052. FILEPATH_DEVICE_PATH *pFP_DP = NULL;
  4053. ULONG fpLength,dpLength;
  4054. PWSTR pFilePathName;
  4055. NTSTATUS Status;
  4056. fpLength = 0;
  4057. dpLength = 0;
  4058. pDevPath = pDevicePath;
  4059. Status = STATUS_INVALID_PARAMETER;
  4060. while( IsDevicePathEndType( pDevPath ) == FALSE ) {
  4061. if( ( DevicePathType( pDevPath ) != MEDIA_DEVICE_PATH ) ||
  4062. ( DevicePathSubType( pDevPath ) != MEDIA_HARDDRIVE_DP ) ) {
  4063. pDevPath = NextDevicePathNode( pDevPath );
  4064. }
  4065. else {
  4066. //
  4067. // return the HardDrive node
  4068. //
  4069. pHD_DP = (HARDDRIVE_DEVICE_PATH UNALIGNED *)pDevPath;
  4070. //
  4071. // Assume successful operations until an error is detected
  4072. //
  4073. Status = STATUS_SUCCESS;
  4074. dpLength += DevicePathNodeLength( pDevPath );
  4075. pDevPath = NextDevicePathNode( pDevPath );
  4076. if( ( DevicePathType( pDevPath ) == MEDIA_DEVICE_PATH ) &&
  4077. ( DevicePathSubType( pDevPath ) == MEDIA_FILEPATH_DP ) ) {
  4078. //
  4079. // return the FilePath node
  4080. //
  4081. pFP_DP = (FILEPATH_DEVICE_PATH *)pDevPath;
  4082. //
  4083. // Sum up the lengths of all PathNames in the
  4084. // FilePath nodes
  4085. //
  4086. do {
  4087. //
  4088. // Length of PathName is
  4089. // FILEPATH_DEVICE_PATH.Length - (offset to PathName field)
  4090. //
  4091. fpLength += (DevicePathNodeLength(pDevPath) -
  4092. FIELD_OFFSET(FILEPATH_DEVICE_PATH, PathName));
  4093. dpLength += DevicePathNodeLength( pDevPath );
  4094. pDevPath = NextDevicePathNode( pDevPath );
  4095. } while( ( DevicePathType( pDevPath ) == MEDIA_DEVICE_PATH ) &&
  4096. ( DevicePathSubType( pDevPath ) == MEDIA_FILEPATH_DP ) );
  4097. }
  4098. //
  4099. // At this point, the node must be a END_DEVICE_PATH
  4100. //
  4101. if( IsDevicePathEndType( pDevPath ) == FALSE ) {
  4102. Status = STATUS_INVALID_PARAMETER;
  4103. }
  4104. break;
  4105. }
  4106. }
  4107. //
  4108. // If no MEDIA/HARDDRIVE element was found, we cannot continue. The
  4109. // MEDIA/FILEPATH element is optional.
  4110. //
  4111. if( !NT_SUCCESS( Status ) ) {
  4112. return( Status );
  4113. }
  4114. //
  4115. // Check the partition type, must be GPT or MBR
  4116. //
  4117. if( pHD_DP->SignatureType == SIGNATURE_TYPE_GUID ) {
  4118. *GPTpartition = TRUE;
  4119. }
  4120. else {
  4121. if ( pHD_DP->SignatureType == SIGNATURE_TYPE_MBR ) {
  4122. *GPTpartition = FALSE;
  4123. }
  4124. else {
  4125. //DbgPrint( "ExpParseEfiPath: partition signature type unknown\n" );
  4126. return( STATUS_INVALID_PARAMETER );
  4127. }
  4128. }
  4129. if( fpLength != 0 ) {
  4130. fpLength += sizeof(WCHAR); // add null-terminator
  4131. pFilePathName = ExAllocatePoolWithTag( NonPagedPool, fpLength, 'rvnE' );
  4132. if( pFilePathName == NULL ) {
  4133. return( STATUS_INSUFFICIENT_RESOURCES );
  4134. }
  4135. wcscpy( pFilePathName, pFP_DP->PathName );
  4136. pDevPath = (EFI_DEVICE_PATH *)pFP_DP;
  4137. pDevPath = NextDevicePathNode( pDevPath );
  4138. while( IsDevicePathEndType( pDevPath ) == FALSE ) {
  4139. pFP_DP = (FILEPATH_DEVICE_PATH *)pDevPath;
  4140. wcscat( pFilePathName, pFP_DP->PathName );
  4141. pDevPath = NextDevicePathNode( pDevPath );
  4142. }
  4143. }
  4144. else {
  4145. pFilePathName = NULL;
  4146. }
  4147. //
  4148. // almost done. allocate an aligned buffer for the device path and copy
  4149. // the unaligned contents into this buffer.
  4150. //
  4151. *ppHardDriveDP = ExAllocatePoolWithTag( NonPagedPool, dpLength, 'rvnE' );
  4152. if (*ppHardDriveDP == NULL) {
  4153. if (pFilePathName) {
  4154. ExFreePool(pFilePathName);
  4155. }
  4156. return( STATUS_INSUFFICIENT_RESOURCES );
  4157. }
  4158. RtlCopyMemory( *ppHardDriveDP, pHD_DP, dpLength );
  4159. *ppPathName = pFilePathName;
  4160. return( Status );
  4161. } // ExpParseEfiPath
  4162. NTSTATUS
  4163. ExpConvertArcName(
  4164. IN ULONG OutputType,
  4165. OUT PFILE_PATH OutputPath,
  4166. IN OUT PULONG OutputPathLength,
  4167. IN PWSTR pDeviceName,
  4168. IN PWSTR pPathName,
  4169. IN ULONG DeviceNameCount
  4170. )
  4171. {
  4172. ULONG requiredCount, requiredLength, filePathLength;
  4173. PWSTR linkName;
  4174. UNICODE_STRING deviceNameString;
  4175. PWCHAR p;
  4176. PFILE_PATH filePath;
  4177. NTSTATUS status;
  4178. //
  4179. // Allocate Pool to hold the ArcName's NT Name
  4180. //
  4181. #define ARC_DIR_PREFIX L"\\ArcName\\"
  4182. #define ARC_DIR_PREFIX_COUNT 9
  4183. requiredCount = DeviceNameCount + ARC_DIR_PREFIX_COUNT + 1;
  4184. requiredLength = requiredCount * sizeof(WCHAR);
  4185. linkName = ExAllocatePoolWithTag( NonPagedPool, requiredLength, 'rvnE' );
  4186. if ( linkName == NULL ) {
  4187. return STATUS_INSUFFICIENT_RESOURCES;
  4188. }
  4189. wcscpy( linkName, ARC_DIR_PREFIX );
  4190. wcsncat( linkName, pDeviceName, DeviceNameCount );
  4191. linkName[ requiredCount - 1 ] = UNICODE_NULL;
  4192. if( OutputType == FILE_PATH_TYPE_NT ) {
  4193. //
  4194. // Open the symbolic link object & drill down to the target
  4195. // return symbolic link target
  4196. //
  4197. status = ExpTranslateSymbolicLink(
  4198. linkName,
  4199. &deviceNameString
  4200. );
  4201. ExFreePool( linkName );
  4202. if ( !NT_SUCCESS(status) ) {
  4203. return( status );
  4204. }
  4205. status = ExpCreateOutputNT(
  4206. OutputPath,
  4207. OutputPathLength,
  4208. &deviceNameString,
  4209. pPathName
  4210. );
  4211. ExFreePool( deviceNameString.Buffer );
  4212. return( status );
  4213. }
  4214. //
  4215. // Output type is either FILE_PATH_TYPE_EFI or FILE_PATH_TYPE_ARC_SIGNATURE
  4216. // and we have a NT name, so use ExpTranslateNtPath() for the conversion
  4217. // Create a input FILE_PATH with the NT name
  4218. //
  4219. filePathLength = requiredLength + FIELD_OFFSET(FILE_PATH, FilePath);
  4220. if ( pPathName != NULL ) {
  4221. filePathLength += ((ULONG)(wcslen( pPathName )) * sizeof(WCHAR));
  4222. }
  4223. filePathLength += sizeof(WCHAR);
  4224. filePath = ExAllocatePoolWithTag( NonPagedPool, filePathLength, 'rvnE' );
  4225. if ( filePath == NULL ) {
  4226. ExFreePool( linkName );
  4227. return STATUS_INSUFFICIENT_RESOURCES;
  4228. }
  4229. //
  4230. // Build the input file path.
  4231. //
  4232. filePath->Version = FILE_PATH_VERSION;
  4233. filePath->Length = filePathLength;
  4234. filePath->Type = FILE_PATH_TYPE_NT;
  4235. p = (PWSTR)filePath->FilePath;
  4236. wcscpy( p, linkName );
  4237. p = (PWSTR)((PUCHAR)p + requiredLength);
  4238. ExFreePool( linkName );
  4239. if ( pPathName != NULL ) {
  4240. wcscpy( p, pPathName );
  4241. }
  4242. else {
  4243. *p = UNICODE_NULL;
  4244. }
  4245. status = ExpTranslateNtPath(
  4246. filePath,
  4247. OutputType,
  4248. OutputPath,
  4249. OutputPathLength
  4250. );
  4251. ExFreePool( filePath );
  4252. return( status );
  4253. } // ExpConvertArcName
  4254. NTSTATUS
  4255. ExpConvertSignatureName(
  4256. IN ULONG OutputType,
  4257. OUT PFILE_PATH OutputPath,
  4258. IN OUT PULONG OutputPathLength,
  4259. IN PWSTR pDeviceName,
  4260. IN PWSTR pPathName,
  4261. IN ULONG DeviceNameCount
  4262. )
  4263. {
  4264. DISK_SIGNATURE_NEW diskSignature;
  4265. ULONG inputPartitionNumber, outputPartitionNumber;
  4266. ULONG diskNumber;
  4267. ULONGLONG inputPartitionStart, outputPartitionStart;
  4268. ULONGLONG inputPartitionSize, outputPartitionSize;
  4269. BOOLEAN GPTpartition, longSignature;
  4270. PWSTR pDiskName;
  4271. UNICODE_STRING DiskNameString;
  4272. NTSTATUS status;
  4273. //
  4274. // Determine the signature() format
  4275. //
  4276. status = ExpParseSignatureName (
  4277. pDeviceName,
  4278. DeviceNameCount,
  4279. &diskSignature,
  4280. &inputPartitionNumber,
  4281. &inputPartitionStart,
  4282. &inputPartitionSize,
  4283. &GPTpartition,
  4284. &longSignature
  4285. );
  4286. if ( !NT_SUCCESS(status) ) {
  4287. return status;
  4288. }
  4289. //
  4290. // if signature(<guid/signature>-<part#>-<start>-<size>) format &&
  4291. // ( OutputType == FILE_PATH_TYPE_EFI )
  4292. // return EFI_DEVICE_PATH format
  4293. //
  4294. if( (longSignature == TRUE) && (OutputType == FILE_PATH_TYPE_EFI) ) {
  4295. status = ExpCreateOutputEFI(
  4296. OutputPath,
  4297. OutputPathLength,
  4298. &diskSignature,
  4299. &inputPartitionNumber,
  4300. &inputPartitionStart,
  4301. &inputPartitionSize,
  4302. pPathName,
  4303. GPTpartition
  4304. );
  4305. return( status );
  4306. }
  4307. //
  4308. // open all disks and search for partition GUID
  4309. //
  4310. if( GPTpartition == FALSE ) {
  4311. outputPartitionNumber = inputPartitionNumber;
  4312. }
  4313. status = ExpFindDiskSignature(
  4314. &diskSignature,
  4315. &outputPartitionNumber,
  4316. &diskNumber,
  4317. &outputPartitionStart,
  4318. &outputPartitionSize,
  4319. GPTpartition
  4320. );
  4321. if ( !NT_SUCCESS(status) ) {
  4322. return status;
  4323. }
  4324. //
  4325. // If the user has provided the partition number, start address,
  4326. // and size; then verify the input with the found results.
  4327. //
  4328. if( (longSignature == TRUE) &&
  4329. ( (inputPartitionNumber != outputPartitionNumber) ||
  4330. (inputPartitionStart != outputPartitionStart) ||
  4331. (inputPartitionSize != outputPartitionSize)
  4332. ) ) {
  4333. return( STATUS_INVALID_PARAMETER );
  4334. }
  4335. if( OutputType == FILE_PATH_TYPE_EFI ) {
  4336. status = ExpCreateOutputEFI(
  4337. OutputPath,
  4338. OutputPathLength,
  4339. &diskSignature,
  4340. &outputPartitionNumber,
  4341. &outputPartitionStart,
  4342. &outputPartitionSize,
  4343. pPathName,
  4344. GPTpartition
  4345. );
  4346. return( status );
  4347. }
  4348. //
  4349. // translate \Device\Harddisk[diskNumber]\Partition[PartitionNumber]
  4350. //
  4351. #define DISK_NAME_FORMAT L"\\Device\\Harddisk%lu\\Partition%lu"
  4352. #define DISK_NAME_COUNT 47 // 7 + 9 + (10) + 10 + (10) + 1
  4353. pDiskName = ExAllocatePoolWithTag(
  4354. NonPagedPool,
  4355. ( DISK_NAME_COUNT * sizeof( WCHAR ) ),
  4356. 'rvnE'
  4357. );
  4358. if( pDiskName == NULL ) {
  4359. return( STATUS_INSUFFICIENT_RESOURCES );
  4360. }
  4361. _snwprintf(
  4362. pDiskName,
  4363. DISK_NAME_COUNT,
  4364. DISK_NAME_FORMAT,
  4365. diskNumber,
  4366. outputPartitionNumber
  4367. );
  4368. status = ExpTranslateSymbolicLink(
  4369. pDiskName,
  4370. &DiskNameString
  4371. );
  4372. ExFreePool( pDiskName );
  4373. if ( !NT_SUCCESS(status) ) {
  4374. return( status );
  4375. }
  4376. if( OutputType == FILE_PATH_TYPE_NT ) {
  4377. status = ExpCreateOutputNT(
  4378. OutputPath,
  4379. OutputPathLength,
  4380. &DiskNameString,
  4381. pPathName
  4382. );
  4383. ExFreePool( DiskNameString.Buffer );
  4384. return( status );
  4385. }
  4386. if( OutputType == FILE_PATH_TYPE_ARC ) {
  4387. status = ExpCreateOutputARC(
  4388. OutputPath,
  4389. OutputPathLength,
  4390. &DiskNameString,
  4391. pPathName
  4392. );
  4393. ExFreePool( DiskNameString.Buffer );
  4394. return( status );
  4395. }
  4396. ExFreePool( DiskNameString.Buffer );
  4397. return( STATUS_INVALID_PARAMETER );
  4398. } // ExpConvertSignatureName
  4399. NTSTATUS
  4400. ExpTranslateHexStringToULONG (
  4401. IN PWSTR Name,
  4402. OUT PULONG Number
  4403. )
  4404. {
  4405. ULONG number;
  4406. ULONG i, max;
  4407. WCHAR c;
  4408. #define ULONG_HEX_MAX 8
  4409. max = (ULONG)wcslen( Name );
  4410. if( max > ULONG_HEX_MAX ) {
  4411. return( STATUS_INVALID_PARAMETER );
  4412. }
  4413. number = 0;
  4414. for (i = 0; i < max; i++) {
  4415. c = towlower(Name[i]);
  4416. if ((c >= L'0') && (c <= L'9')) {
  4417. number = (number * 16) + (c - L'0');
  4418. } else if ((c >= L'a') && (c <= L'f')) {
  4419. number = (number * 16) + (c - L'a' + 10);
  4420. } else {
  4421. return( STATUS_INVALID_PARAMETER );
  4422. }
  4423. }
  4424. *Number = number;
  4425. return( STATUS_SUCCESS );
  4426. } // ExpTranslateHexStringToULONG
  4427. NTSTATUS
  4428. ExpTranslateHexStringToULONGLONG (
  4429. IN PWSTR Name,
  4430. OUT PULONGLONG Number
  4431. )
  4432. {
  4433. ULONGLONG number;
  4434. ULONG i, max;
  4435. WCHAR c;
  4436. #define ULONGLONG_HEX_MAX 16
  4437. max = (ULONG)wcslen( Name );
  4438. if( max > ULONGLONG_HEX_MAX ) {
  4439. return( STATUS_INVALID_PARAMETER );
  4440. }
  4441. number = 0;
  4442. for (i = 0; i < max; i++) {
  4443. c = towlower(Name[i]);
  4444. if ((c >= L'0') && (c <= L'9')) {
  4445. number = (number * 16) + (c - L'0');
  4446. } else if ((c >= L'a') && (c <= L'f')) {
  4447. number = (number * 16) + (c - L'a' + 10);
  4448. } else {
  4449. return( STATUS_INVALID_PARAMETER );
  4450. }
  4451. }
  4452. *Number = number;
  4453. return( STATUS_SUCCESS );
  4454. } // ExpTranslateHexStringToULONGLONG
  4455. NTSTATUS
  4456. ExpTranslateHexStringToGUID (
  4457. IN PWSTR Name,
  4458. OUT GUID *pGuid
  4459. )
  4460. {
  4461. GUID resultGuid;
  4462. ULONG i, max, number, result;
  4463. USHORT formatStyle, position;
  4464. WCHAR c;
  4465. #define GUID_HEX_MAX 32
  4466. max = (ULONG)wcslen( Name );
  4467. if( max != GUID_HEX_MAX ) {
  4468. return( STATUS_INVALID_PARAMETER );
  4469. }
  4470. number = 0;
  4471. formatStyle = 0;
  4472. position = 0;
  4473. result = 0;
  4474. for (i = 0; i < max; i++) {
  4475. c = towlower(Name[i]);
  4476. if ((c >= L'0') && (c <= L'9')) {
  4477. number = (number * 16) + (c - L'0');
  4478. } else if ((c >= L'a') && (c <= L'f')) {
  4479. number = (number * 16) + (c - L'a' + 10);
  4480. } else {
  4481. return( STATUS_INVALID_PARAMETER );
  4482. }
  4483. if ((i % 2) == 1) {
  4484. switch( formatStyle ) {
  4485. case 0:
  4486. result += (number << (position * 8));
  4487. position++;
  4488. if( position == 4 ) {
  4489. resultGuid.Data1 = result;
  4490. formatStyle++;
  4491. position = 0;
  4492. result = 0;
  4493. }
  4494. break;
  4495. case 1:
  4496. result += (number << (position * 8));
  4497. position++;
  4498. if( position == 2 ) {
  4499. resultGuid.Data2 = (USHORT)result;
  4500. formatStyle++;
  4501. position = 0;
  4502. result = 0;
  4503. }
  4504. break;
  4505. case 2:
  4506. result += (number << (position * 8));
  4507. position++;
  4508. if( position == 2 ) {
  4509. resultGuid.Data3 = (USHORT)result;
  4510. formatStyle++;
  4511. position = 0;
  4512. result = 0;
  4513. }
  4514. break;
  4515. case 3:
  4516. resultGuid.Data4[ position ] = (UCHAR)number;
  4517. position++;
  4518. if( position == 8 ) {
  4519. formatStyle++;
  4520. }
  4521. break;
  4522. default:
  4523. return( STATUS_INVALID_PARAMETER );
  4524. break;
  4525. }
  4526. number = 0;
  4527. }
  4528. }
  4529. memcpy(pGuid, &(resultGuid), sizeof(GUID));
  4530. return( STATUS_SUCCESS );
  4531. } // ExpTranslateHexStringToGUID
  4532. NTSTATUS
  4533. ExpCreateOutputEFI (
  4534. OUT PFILE_PATH OutputPath,
  4535. IN OUT PULONG OutputPathLength,
  4536. IN PDISK_SIGNATURE_NEW pDiskSignature,
  4537. IN PULONG pPartitionNumber,
  4538. IN PULONGLONG pPartitionStart,
  4539. IN PULONGLONG pPartitionSize,
  4540. IN PWSTR pPathName,
  4541. IN BOOLEAN GPTpartition
  4542. )
  4543. {
  4544. ULONG requiredLength, pathNameLength = 0;
  4545. EFI_DEVICE_PATH *dp;
  4546. HARDDRIVE_DEVICE_PATH UNALIGNED *dpHarddrive = NULL;
  4547. FILEPATH_DEVICE_PATH *dpFilepath = NULL;
  4548. //
  4549. // The output EFI file path consists of two elements. First is a
  4550. // MEDIA/HARDDRIVE element describing the partition. Second is an
  4551. // optional MEDIA/FILEPATH element describing the path to a directory
  4552. // or a file.
  4553. //
  4554. requiredLength = FIELD_OFFSET(FILE_PATH, FilePath);
  4555. requiredLength += sizeof(HARDDRIVE_DEVICE_PATH);
  4556. if (pPathName != NULL) {
  4557. pathNameLength = (ULONG)wcslen(pPathName);
  4558. pathNameLength = (pathNameLength + 1) * sizeof(WCHAR);
  4559. requiredLength += FIELD_OFFSET(FILEPATH_DEVICE_PATH, PathName);
  4560. requiredLength += pathNameLength;
  4561. }
  4562. requiredLength += sizeof(EFI_DEVICE_PATH);
  4563. //
  4564. // Compare the required length against the output buffer length.
  4565. //
  4566. if ( *OutputPathLength < requiredLength ) {
  4567. *OutputPathLength = requiredLength;
  4568. return STATUS_BUFFER_TOO_SMALL;
  4569. }
  4570. //
  4571. // Build the output file path.
  4572. //
  4573. OutputPath->Version = FILE_PATH_VERSION;
  4574. OutputPath->Length = requiredLength;
  4575. OutputPath->Type = FILE_PATH_TYPE_EFI;
  4576. dp = (EFI_DEVICE_PATH *)OutputPath->FilePath;
  4577. dpHarddrive = (HARDDRIVE_DEVICE_PATH UNALIGNED *)dp;
  4578. dp->Type = MEDIA_DEVICE_PATH;
  4579. dp->SubType = MEDIA_HARDDRIVE_DP;
  4580. SetDevicePathNodeLength(dp, sizeof(HARDDRIVE_DEVICE_PATH));
  4581. dpHarddrive->PartitionNumber = *pPartitionNumber;
  4582. dpHarddrive->PartitionStart = *pPartitionStart;
  4583. dpHarddrive->PartitionSize = *pPartitionSize;
  4584. if (GPTpartition == TRUE) {
  4585. memcpy(dpHarddrive->Signature, &(pDiskSignature->Guid), sizeof(GUID));
  4586. dpHarddrive->MBRType = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
  4587. dpHarddrive->SignatureType = SIGNATURE_TYPE_GUID;
  4588. } else {
  4589. memcpy(dpHarddrive->Signature, &(pDiskSignature->Signature), sizeof(ULONG));
  4590. dpHarddrive->MBRType = MBR_TYPE_PCAT;
  4591. dpHarddrive->SignatureType = SIGNATURE_TYPE_MBR;
  4592. }
  4593. if (pPathName != NULL) {
  4594. dp = NextDevicePathNode(dp);
  4595. dpFilepath = (FILEPATH_DEVICE_PATH *)dp;
  4596. dp->Type = MEDIA_DEVICE_PATH;
  4597. dp->SubType = MEDIA_FILEPATH_DP;
  4598. SetDevicePathNodeLength(dp, FIELD_OFFSET(FILEPATH_DEVICE_PATH, PathName) + pathNameLength);
  4599. wcscpy(dpFilepath->PathName, pPathName);
  4600. }
  4601. dp = NextDevicePathNode(dp);
  4602. SetDevicePathEndNode(dp);
  4603. *OutputPathLength = requiredLength;
  4604. return STATUS_SUCCESS;
  4605. } // ExpCreateOutputEFI
  4606. NTSTATUS
  4607. ExpCreateOutputNT (
  4608. OUT PFILE_PATH OutputPath,
  4609. IN OUT PULONG OutputPathLength,
  4610. IN PUNICODE_STRING pDeviceNameString,
  4611. IN PWSTR pPathName
  4612. )
  4613. {
  4614. ULONG requiredLength;
  4615. PWCHAR p;
  4616. requiredLength = pDeviceNameString->Length + sizeof(WCHAR);
  4617. //
  4618. // If a PathName component is present, then increase the
  4619. // output string length by the length of the path string.
  4620. //
  4621. if ( pPathName != NULL ) {
  4622. requiredLength += ((ULONG)(wcslen( pPathName )) * sizeof(WCHAR));
  4623. }
  4624. //
  4625. // always add a UNICODE_NULL for PathName even if PathName is not present
  4626. //
  4627. requiredLength += sizeof(WCHAR);
  4628. //
  4629. // Add the structure overhead and compare the required length against
  4630. // output buffer length.
  4631. //
  4632. requiredLength += FIELD_OFFSET(FILE_PATH, FilePath);
  4633. if ( *OutputPathLength < requiredLength ) {
  4634. *OutputPathLength = requiredLength;
  4635. return STATUS_BUFFER_TOO_SMALL;
  4636. }
  4637. //
  4638. // Build the output file path.
  4639. //
  4640. OutputPath->Version = FILE_PATH_VERSION;
  4641. OutputPath->Length = requiredLength;
  4642. OutputPath->Type = FILE_PATH_TYPE_NT;
  4643. p = (PWSTR)OutputPath->FilePath;
  4644. wcscpy( p, pDeviceNameString->Buffer );
  4645. p = (PWSTR)((PUCHAR)p + pDeviceNameString->Length + sizeof(WCHAR));
  4646. if ( pPathName != NULL ) {
  4647. wcscpy( p, pPathName );
  4648. }
  4649. else {
  4650. *p = UNICODE_NULL;
  4651. }
  4652. *OutputPathLength = requiredLength;
  4653. return STATUS_SUCCESS;
  4654. } // ExpCreateOutputNT
  4655. NTSTATUS
  4656. ExpCreateOutputARC (
  4657. OUT PFILE_PATH OutputPath,
  4658. IN OUT PULONG OutputPathLength,
  4659. IN PUNICODE_STRING pDeviceNameString,
  4660. IN PWSTR pPathName
  4661. )
  4662. {
  4663. ULONG requiredLength, ArcNameLength;
  4664. PWCHAR p;
  4665. PWSTR pArcDeviceName;
  4666. NTSTATUS status;
  4667. status = ExpFindArcName(
  4668. pDeviceNameString,
  4669. &pArcDeviceName
  4670. );
  4671. if (!NT_SUCCESS(status)) {
  4672. return( status );
  4673. }
  4674. ArcNameLength = ((ULONG)wcslen(pArcDeviceName)) * sizeof(WCHAR);
  4675. requiredLength = ArcNameLength + sizeof(WCHAR);
  4676. //
  4677. // If a PathName component is present, then increase the
  4678. // output string length by the length of the path string.
  4679. //
  4680. if ( pPathName != NULL ) {
  4681. requiredLength += ((ULONG)(wcslen( pPathName )) * sizeof(WCHAR));
  4682. }
  4683. //
  4684. // Add the structure overhead and compare the required length against
  4685. // output buffer length.
  4686. //
  4687. requiredLength += FIELD_OFFSET(FILE_PATH, FilePath);
  4688. if ( *OutputPathLength < requiredLength ) {
  4689. *OutputPathLength = requiredLength;
  4690. ExFreePool( pArcDeviceName );
  4691. return STATUS_BUFFER_TOO_SMALL;
  4692. }
  4693. //
  4694. // Build the output file path.
  4695. //
  4696. OutputPath->Version = FILE_PATH_VERSION;
  4697. OutputPath->Length = requiredLength;
  4698. OutputPath->Type = FILE_PATH_TYPE_ARC;
  4699. p = (PWSTR)OutputPath->FilePath;
  4700. wcscpy( p, pArcDeviceName );
  4701. p = (PWSTR)((PUCHAR)p + ArcNameLength);
  4702. ExFreePool( pArcDeviceName );
  4703. if ( pPathName != NULL ) {
  4704. wcscpy( p, pPathName );
  4705. }
  4706. *OutputPathLength = requiredLength;
  4707. return STATUS_SUCCESS;
  4708. } // ExpCreateOutputARC
  4709. NTSTATUS
  4710. ExpCreateOutputSIGNATURE (
  4711. OUT PFILE_PATH OutputPath,
  4712. IN OUT PULONG OutputPathLength,
  4713. IN PDISK_SIGNATURE_NEW pDiskSignature,
  4714. IN PULONG pPartitionNumber,
  4715. IN PULONGLONG pPartitionStart,
  4716. IN PULONGLONG pPartitionSize,
  4717. IN PWSTR pPathName,
  4718. IN BOOLEAN GPTpartition
  4719. )
  4720. {
  4721. ULONG requiredLength, pathNameCount;
  4722. PWCHAR p;
  4723. UNICODE_STRING GuidString;
  4724. NTSTATUS status;
  4725. //
  4726. // We will convert the EFI device path into an ARC name with this
  4727. // format:
  4728. //
  4729. // signature(<guid/signature>-<part#>-<start>-<size>)
  4730. //
  4731. // Where:
  4732. //
  4733. // <guid/signature> - For a GPT disk, the GPT partition GUID in
  4734. // "pretty" format ({33221100-5544-7766-8899-aabbccddeeff}).
  4735. // For an MBR disk, 8 hex digits representing the ULONG MBR
  4736. // disk signature. (Formatted using %08x.)
  4737. // <part#> - 8 hex digits representing the ULONG partition number.
  4738. // (Formatted using %08x.)
  4739. // <start> - 16 hex digits representing the ULONGLONG starting LBA.
  4740. // (Formatted using %016I64x.)
  4741. // <size> - 16 hex digits representing the ULONGLONG partition size.
  4742. // (Formatted using %016I64x.)
  4743. //
  4744. // For a GPT disk, the output string length is 86 WCHARs. For an
  4745. // MBR disk, the output string length is 62 WCHARs.
  4746. //
  4747. requiredLength = (ULONG)strlen("signature(") +
  4748. 1 + // "-"
  4749. (sizeof(ULONG) * 2) + // <part#>
  4750. 1 + // "-"
  4751. (sizeof(ULONGLONG) * 2) + // <start>
  4752. 1 + // "-"
  4753. (sizeof(ULONGLONG) * 2) + // <size>
  4754. 1 + // ")"
  4755. 1; // null terminator
  4756. if ( GPTpartition == TRUE ) {
  4757. requiredLength += (sizeof(GUID) * 2);
  4758. requiredLength += 6; // for the {} & four '-' in the pretty GUID format
  4759. } else {
  4760. requiredLength += sizeof(ULONG) * 2;
  4761. }
  4762. //
  4763. // If a pathName component is present, then increase the
  4764. // output string length by the length of the path string.
  4765. //
  4766. if (pPathName != NULL) {
  4767. pathNameCount = (ULONG)wcslen(pPathName);
  4768. requiredLength += pathNameCount;
  4769. }
  4770. else {
  4771. pathNameCount = 0;
  4772. }
  4773. //
  4774. // Convert the string length to a byte count, add the structure
  4775. // overhead, and compare the required length against output buffer
  4776. // length.
  4777. //
  4778. requiredLength *= sizeof(WCHAR);
  4779. requiredLength += FIELD_OFFSET(FILE_PATH, FilePath);
  4780. if ( *OutputPathLength < requiredLength ) {
  4781. *OutputPathLength = requiredLength;
  4782. return STATUS_BUFFER_TOO_SMALL;
  4783. }
  4784. //
  4785. // Build the output file path.
  4786. //
  4787. OutputPath->Version = FILE_PATH_VERSION;
  4788. OutputPath->Length = requiredLength;
  4789. OutputPath->Type = FILE_PATH_TYPE_ARC_SIGNATURE;
  4790. p = (PWSTR)OutputPath->FilePath;
  4791. wcscpy( p, L"signature(" );
  4792. p += wcslen( p );
  4793. if ( GPTpartition == TRUE ) {
  4794. status = RtlStringFromGUID(
  4795. (LPGUID)(&(pDiskSignature->Guid)),
  4796. &GuidString
  4797. );
  4798. if ( !NT_SUCCESS(status) ) {
  4799. return status;
  4800. }
  4801. wcscat( p, GuidString.Buffer );
  4802. p = (PWCHAR)((PUCHAR)p + GuidString.Length);
  4803. ExFreePool( GuidString.Buffer );
  4804. } else {
  4805. swprintf( p, L"%08x", pDiskSignature->Signature );
  4806. p += wcslen( p );
  4807. }
  4808. swprintf(
  4809. p,
  4810. L"-%08x-%016I64x-%016I64x)",
  4811. *pPartitionNumber,
  4812. *pPartitionStart,
  4813. *pPartitionSize
  4814. );
  4815. p += wcslen( p );
  4816. if ( pathNameCount != 0 ) {
  4817. wcscpy( p, pPathName );
  4818. }
  4819. *OutputPathLength = requiredLength;
  4820. return STATUS_SUCCESS;
  4821. } // ExpCreateOutputSIGNATURE
  4822. NTSTATUS
  4823. ExpFindArcName (
  4824. IN PUNICODE_STRING pDeviceNameString,
  4825. OUT PWSTR *pArcName
  4826. )
  4827. {
  4828. NTSTATUS status;
  4829. UNICODE_STRING ArcString, SymLinkTypeString;
  4830. OBJECT_ATTRIBUTES Attributes;
  4831. PWSTR pArcDirName, pArcLinkName;
  4832. HANDLE hArcDirectory;
  4833. POBJECT_DIRECTORY_INFORMATION pDirInfo;
  4834. ULONG dirInfoLength, neededLength, dirContext;
  4835. ULONG arcNameCount;
  4836. BOOLEAN restartScan, ArcNameFound = FALSE;
  4837. //
  4838. // Open a handle to the directory object for \ArcName
  4839. // Get a kernel handle
  4840. //
  4841. #define ARC_DIR_NAME L"\\ArcName"
  4842. #define ARC_DIR_SIZE (9 * sizeof(WCHAR))
  4843. #define ARC_DIR_NAME_PREFIX L"\\ArcName\\"
  4844. #define ARC_DIR_SIZE_PREFIX (9 * sizeof(WCHAR))
  4845. pArcDirName = ExAllocatePoolWithTag( NonPagedPool, ARC_DIR_SIZE, 'rvnE' );
  4846. if ( pArcDirName == NULL ) {
  4847. return( STATUS_INSUFFICIENT_RESOURCES );
  4848. }
  4849. wcscpy( pArcDirName, ARC_DIR_NAME );
  4850. RtlInitUnicodeString( &ArcString, pArcDirName );
  4851. InitializeObjectAttributes(
  4852. &Attributes,
  4853. &ArcString,
  4854. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  4855. NULL,
  4856. NULL
  4857. );
  4858. status = ZwOpenDirectoryObject(
  4859. &hArcDirectory,
  4860. DIRECTORY_QUERY,
  4861. &Attributes
  4862. );
  4863. ExFreePool( pArcDirName );
  4864. if (!NT_SUCCESS(status)) {
  4865. return( status );
  4866. }
  4867. pDirInfo = NULL;
  4868. dirInfoLength = 0;
  4869. restartScan = TRUE;
  4870. RtlInitUnicodeString( &SymLinkTypeString, L"SymbolicLink" );
  4871. while (TRUE) {
  4872. status = ZwQueryDirectoryObject(
  4873. hArcDirectory,
  4874. pDirInfo,
  4875. dirInfoLength,
  4876. TRUE, // force one at a time
  4877. restartScan,
  4878. &dirContext,
  4879. &neededLength
  4880. );
  4881. if (status == STATUS_BUFFER_TOO_SMALL) {
  4882. dirInfoLength = neededLength;
  4883. if (pDirInfo != NULL) {
  4884. ExFreePool(pDirInfo);
  4885. }
  4886. pDirInfo = ExAllocatePoolWithTag( NonPagedPool, dirInfoLength, 'rvnE' );
  4887. if (pDirInfo == NULL) {
  4888. status = STATUS_INSUFFICIENT_RESOURCES;
  4889. break;
  4890. }
  4891. status = ZwQueryDirectoryObject(
  4892. hArcDirectory,
  4893. pDirInfo,
  4894. dirInfoLength,
  4895. TRUE, // force one at a time
  4896. restartScan,
  4897. &dirContext,
  4898. &neededLength
  4899. );
  4900. }
  4901. restartScan = FALSE;
  4902. if (!NT_SUCCESS(status)) {
  4903. if (status == STATUS_NO_MORE_ENTRIES) {
  4904. status = STATUS_SUCCESS;
  4905. }
  4906. break;
  4907. }
  4908. //
  4909. // Check if the element is not a symbolic link
  4910. //
  4911. if (RtlEqualUnicodeString(
  4912. &(pDirInfo->TypeName),
  4913. &SymLinkTypeString,
  4914. FALSE) == FALSE) {
  4915. continue;
  4916. }
  4917. neededLength = ARC_DIR_SIZE_PREFIX + pDirInfo->Name.Length;
  4918. pArcLinkName = ExAllocatePoolWithTag(
  4919. NonPagedPool,
  4920. neededLength + sizeof(WCHAR),
  4921. 'rvnE' );
  4922. if ( pArcLinkName == NULL ) {
  4923. status = STATUS_INSUFFICIENT_RESOURCES;
  4924. break;
  4925. }
  4926. arcNameCount = pDirInfo->Name.Length/sizeof(WCHAR);
  4927. wcscpy( pArcLinkName, ARC_DIR_NAME_PREFIX );
  4928. wcsncat(
  4929. pArcLinkName,
  4930. pDirInfo->Name.Buffer,
  4931. arcNameCount
  4932. );
  4933. pArcLinkName[ neededLength/sizeof(WCHAR) ] = UNICODE_NULL;
  4934. //
  4935. // Drill down this symbolic link to the device object
  4936. //
  4937. status = ExpTranslateSymbolicLink(
  4938. pArcLinkName,
  4939. &ArcString
  4940. );
  4941. if ( !NT_SUCCESS(status) ) {
  4942. ExFreePool( pArcLinkName );
  4943. break;
  4944. }
  4945. //
  4946. // Check if this Arc Name points the same device object
  4947. //
  4948. ArcNameFound = RtlEqualUnicodeString(
  4949. &ArcString,
  4950. pDeviceNameString,
  4951. TRUE
  4952. );
  4953. ExFreePool( ArcString.Buffer );
  4954. if (ArcNameFound == TRUE) {
  4955. //
  4956. // copy the arc name without the \ArcName\ prefix
  4957. //
  4958. wcsncpy(
  4959. pArcLinkName,
  4960. pDirInfo->Name.Buffer,
  4961. arcNameCount
  4962. );
  4963. pArcLinkName[ arcNameCount ] = UNICODE_NULL;
  4964. *pArcName = pArcLinkName;
  4965. break;
  4966. }
  4967. ExFreePool( pArcLinkName );
  4968. }
  4969. if( NT_SUCCESS(status) && (ArcNameFound == FALSE ) ) {
  4970. status = STATUS_OBJECT_PATH_NOT_FOUND;
  4971. }
  4972. if (pDirInfo != NULL) {
  4973. ExFreePool(pDirInfo);
  4974. }
  4975. ZwClose( hArcDirectory );
  4976. return( status );
  4977. } // ExpFindArcName
  4978. NTSTATUS
  4979. ExpFindDiskSignature (
  4980. IN PDISK_SIGNATURE_NEW pSignature,
  4981. IN OUT PULONG pPartitionNumber,
  4982. OUT PULONG pDiskNumber,
  4983. OUT PULONGLONG pPartitionStart,
  4984. OUT PULONGLONG pPartitionSize,
  4985. IN BOOLEAN GPTpartition
  4986. )
  4987. /*++
  4988. Routine Description:
  4989. This function searches all the disks on the system for the
  4990. partition corresponding to the paritition GUID or
  4991. (MBR signature, paritition number).
  4992. N.B. for a MBR signature, the partition number must be provided.
  4993. Arguments:
  4994. pSignature - Supplies a pointer to a partition GUID (GPT disk) or
  4995. 32-bit signature(MBR disk).
  4996. pPartitionNumber - Supplies a pointer to a partition number when
  4997. pSignature is a MBR signature. For output, receives the
  4998. partition number.
  4999. pDiskNumber - Receives the disk number
  5000. pPartitionStart - Receives the start of the partition
  5001. pPartitionSize - Receives the size of the partition
  5002. GPTpartition - Supplies the type of partition
  5003. TRUE - GPT disk partition
  5004. FALSE - MBR disk partition
  5005. Return Value:
  5006. STATUS_SUCCESS is returned if the partition is successfully found.
  5007. STATUS_OBJECT_PATH_NOT_FOUND is returned if the partition could not
  5008. be found.
  5009. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources exist
  5010. for this request to complete.
  5011. --*/
  5012. {
  5013. PDRIVE_LAYOUT_INFORMATION_EX pDriveLayout = NULL;
  5014. PPARTITION_INFORMATION_EX pPartitionInfoEx = NULL;
  5015. SYSTEM_DEVICE_INFORMATION SysDevInfo;
  5016. ULONG PartitionStyle;
  5017. BOOLEAN PartitionFound = FALSE;
  5018. ULONG Index, PartitionIndex;
  5019. PWSTR pDeviceName;
  5020. NTSTATUS Status;
  5021. //
  5022. // Find all disks on the system
  5023. //
  5024. Status = ZwQuerySystemInformation(
  5025. SystemDeviceInformation,
  5026. &SysDevInfo,
  5027. sizeof(SYSTEM_DEVICE_INFORMATION),
  5028. NULL
  5029. );
  5030. if( !NT_SUCCESS( Status ) ) {
  5031. return( Status );
  5032. }
  5033. #define DEVICE_NAME_FORMAT L"\\Device\\Harddisk%lu\\Partition0"
  5034. #define DEVICE_NAME_CHAR_COUNT 38 // 7 + 9 + (10) + 11 + 1
  5035. //
  5036. // Allocate the buffer for the disk names
  5037. //
  5038. pDeviceName = ExAllocatePoolWithTag(
  5039. NonPagedPool,
  5040. ( DEVICE_NAME_CHAR_COUNT * sizeof( WCHAR ) ),
  5041. 'rvnE'
  5042. );
  5043. if( pDeviceName == NULL ) {
  5044. return( STATUS_INSUFFICIENT_RESOURCES );
  5045. }
  5046. if( GPTpartition == TRUE ) {
  5047. PartitionStyle = PARTITION_STYLE_GPT;
  5048. }
  5049. else {
  5050. PartitionStyle = PARTITION_STYLE_MBR;
  5051. }
  5052. //
  5053. // For each disk,
  5054. // Get the Partition Table
  5055. // Verify the partition style (MBR/GPT)
  5056. //
  5057. // if( Partition style matches )
  5058. // search for the Partition in the drive layout
  5059. // else
  5060. // skip the disk
  5061. //
  5062. for( Index = 0; Index < SysDevInfo.NumberOfDisks; Index++ ) {
  5063. //
  5064. // Form the disk name
  5065. // \Device\Harddisk[DiskNumber]\Partition0
  5066. //
  5067. _snwprintf(
  5068. pDeviceName,
  5069. DEVICE_NAME_CHAR_COUNT,
  5070. DEVICE_NAME_FORMAT,
  5071. Index
  5072. );
  5073. Status = ExpGetPartitionTableInfo(
  5074. pDeviceName,
  5075. &pDriveLayout
  5076. );
  5077. if( !NT_SUCCESS( Status ) ) {
  5078. continue;
  5079. }
  5080. if( pDriveLayout->PartitionStyle != PartitionStyle ) {
  5081. ExFreePool( pDriveLayout );
  5082. continue;
  5083. }
  5084. if( (PartitionStyle == PARTITION_STYLE_MBR) &&
  5085. (pDriveLayout->Mbr.Signature != pSignature->Signature) ) {
  5086. ExFreePool( pDriveLayout );
  5087. continue;
  5088. }
  5089. //
  5090. // search partition list
  5091. //
  5092. for( PartitionIndex = 0;
  5093. PartitionIndex < pDriveLayout->PartitionCount;
  5094. PartitionIndex++ ) {
  5095. //
  5096. // Get the partition entry
  5097. //
  5098. pPartitionInfoEx = (&(pDriveLayout->PartitionEntry[PartitionIndex]));
  5099. if( PartitionStyle == PARTITION_STYLE_MBR ) {
  5100. if (pPartitionInfoEx->PartitionNumber == *pPartitionNumber) {
  5101. PartitionFound = TRUE;
  5102. break;
  5103. }
  5104. }
  5105. else {
  5106. if (IsEqualGUID( &(pPartitionInfoEx->Gpt.PartitionId),
  5107. &(pSignature->Guid) )) {
  5108. PartitionFound = TRUE;
  5109. break;
  5110. }
  5111. }
  5112. }
  5113. if( PartitionFound == TRUE ) {
  5114. break;
  5115. }
  5116. ExFreePool( pDriveLayout );
  5117. }
  5118. if( NT_SUCCESS( Status ) && ( PartitionFound == FALSE ) ) {
  5119. Status = STATUS_OBJECT_PATH_NOT_FOUND;
  5120. }
  5121. //
  5122. // Partition Found - copy the needed information
  5123. //
  5124. if( PartitionFound == TRUE ) {
  5125. *pPartitionNumber = pPartitionInfoEx->PartitionNumber;
  5126. *pDiskNumber = Index;
  5127. *pPartitionStart = pPartitionInfoEx->StartingOffset.QuadPart;
  5128. *pPartitionSize = pPartitionInfoEx->PartitionLength.QuadPart;
  5129. ExFreePool( pDriveLayout );
  5130. }
  5131. ExFreePool( pDeviceName );
  5132. return( Status );
  5133. } // ExpFindDiskSignature
  5134. NTSTATUS
  5135. ExpGetPartitionTableInfo (
  5136. IN PWSTR pDeviceName,
  5137. OUT PDRIVE_LAYOUT_INFORMATION_EX *ppDriveLayout
  5138. )
  5139. {
  5140. NTSTATUS status;
  5141. UNICODE_STRING string;
  5142. OBJECT_ATTRIBUTES obja;
  5143. IO_STATUS_BLOCK iosb;
  5144. HANDLE handle;
  5145. PDRIVE_LAYOUT_INFORMATION_EX driveLayoutInfo = NULL;
  5146. ULONG driveLayoutLength;
  5147. //
  5148. // Open the disk and get its partition table information.
  5149. //
  5150. RtlInitUnicodeString(&string, pDeviceName);
  5151. InitializeObjectAttributes(
  5152. &obja,
  5153. &string,
  5154. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  5155. NULL,
  5156. NULL
  5157. );
  5158. status = ZwOpenFile(
  5159. &handle,
  5160. FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  5161. &obja,
  5162. &iosb,
  5163. FILE_SHARE_READ | FILE_SHARE_WRITE,
  5164. FILE_NON_DIRECTORY_FILE
  5165. );
  5166. if (!NT_SUCCESS(status)) {
  5167. return status;
  5168. }
  5169. driveLayoutLength = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry) +
  5170. (sizeof(PARTITION_INFORMATION_EX) * 16);
  5171. while (TRUE) {
  5172. driveLayoutInfo = ExAllocatePoolWithTag(NonPagedPool, driveLayoutLength, 'rvnE');
  5173. if (driveLayoutInfo == NULL ) {
  5174. ZwClose(handle);
  5175. return STATUS_INSUFFICIENT_RESOURCES;
  5176. }
  5177. status = ZwDeviceIoControlFile(
  5178. handle,
  5179. NULL,
  5180. NULL,
  5181. NULL,
  5182. &iosb,
  5183. IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
  5184. NULL,
  5185. 0,
  5186. driveLayoutInfo,
  5187. driveLayoutLength
  5188. );
  5189. if (NT_SUCCESS(status)) {
  5190. break;
  5191. }
  5192. ExFreePool(driveLayoutInfo);
  5193. if (status == STATUS_BUFFER_TOO_SMALL) {
  5194. driveLayoutLength *= 2;
  5195. continue;
  5196. }
  5197. ZwClose(handle);
  5198. return status;
  5199. }
  5200. *ppDriveLayout = driveLayoutInfo;
  5201. ZwClose(handle);
  5202. return status;
  5203. } // ExpGetPartitionTableInfo
  5204. #endif // defined(EFI_NVRAM_ENABLED)