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.

955 lines
27 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1998.
  5. //
  6. // File: acpienab.cpp
  7. //
  8. // Contents: Functions to enable ACPI on a machine which has had NT5
  9. // installed in legacy mode
  10. //
  11. // Notes:
  12. //
  13. // Author: t-sdey 17 July 98
  14. //
  15. //----------------------------------------------------------------------------
  16. #include <winnt32.h>
  17. #include <devguid.h>
  18. extern "C" {
  19. #include <cfgmgr32.h>
  20. #include "idchange.h"
  21. }
  22. #include "acpienab.h"
  23. #include "acpirsrc.h"
  24. // Global Variables
  25. HINSTANCE g_hinst;
  26. TCHAR g_ACPIENAB_INF[] = TEXT(".\\acpienab.inf"); // local directory
  27. TCHAR g_LAYOUT_INF[] = TEXT("layout.inf"); // winnt\inf directory
  28. TCHAR g_HAL_BACKUP[] = TEXT("hal-old.dll");
  29. //+---------------------------------------------------------------------------
  30. //
  31. // Function: WinMain
  32. //
  33. // Purpose: Run everything
  34. //
  35. // Arguments: Standard WinMain arguments
  36. //
  37. // Author: t-sdey 27 July 98
  38. //
  39. // Notes:
  40. //
  41. int WINAPI WinMain(HINSTANCE hInstance,
  42. HINSTANCE hPrevInstance,
  43. LPSTR lpCmdLine,
  44. int nCmdShow)
  45. {
  46. g_hinst = hInstance;
  47. // Enable ACPI
  48. ACPIEnable();
  49. return TRUE;
  50. }
  51. // ----------------------------------------------------------------------
  52. //
  53. // Function: ACPIEnable
  54. //
  55. // Purpose: This function performs the steps necessary to enable ACPI
  56. // and bring the system to a point where the user can log in
  57. // after rebooting. It leaves finding "new" hardware to after
  58. // the user has rebooted and logged in again.
  59. //
  60. // Arguments:
  61. //
  62. // Returns: S_OK if successful
  63. // S_FALSE if unsuccessful
  64. //
  65. // Author: t-sdey 27 July 98
  66. //
  67. // Notes:
  68. //
  69. HRESULT ACPIEnable()
  70. {
  71. //
  72. // These steps are in order from least to most crucial to the stability
  73. // of the system, in case of errors.
  74. //
  75. // Step 1: Test to see if ACPI can be enabled and warn the user to close
  76. // everything else.
  77. // Step 2: Prepare a safe configuration in case of errors.
  78. // Step 3: Set up keyboard and mouse for use after reboot. This involves
  79. // removing them from the CriticalDeviceDatabase so that they will
  80. // be reconfigured (according to the new ACPI layout) after reboot.
  81. // The current keyboards and mice are in the CDD, but we must
  82. // populate it with all possibilities, because their HardwareIDs
  83. // will probably change once ACPI is enabled.
  84. // Step 4: Add new values to the registry:
  85. // - Add ACPI to the CriticalDeviceDatabase
  86. // - Add keyboards and mice to the CriticalDeviceDatabase
  87. // - Enable ACPI in the registry
  88. // Step 5: Copy the ACPI driver.
  89. // Step 6: Copy the new HAL.
  90. // Step 7: Reboot.
  91. //
  92. //
  93. // Step 1: Test to see if ACPI can be enabled and warn the user to close
  94. // everything else.
  95. //
  96. // Make sure the user has administrative access
  97. if (!IsAdministrator()) {
  98. DisplayDialogBox(ACPI_STR_ERROR_DIALOG_CAPTION,
  99. ACPI_STR_ADMIN_ACCESS_REQUIRED,
  100. MB_OK | MB_ICONERROR);
  101. return S_FALSE;
  102. }
  103. // Test to see if ACPI is supported on this architecture
  104. SYSTEM_INFO SystemInfo; // Will be used later to determine HAL
  105. GetSystemInfo(&SystemInfo);
  106. if (SystemInfo.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL) {
  107. // Not supported
  108. DisplayDialogBox(ACPI_STR_ERROR_DIALOG_CAPTION,
  109. ACPI_STR_NOT_SUPPORTED,
  110. MB_OK | MB_ICONERROR);
  111. return S_FALSE;
  112. }
  113. // Warn the user to shut down any other programs
  114. if (DisplayDialogBox(ACPI_STR_WARNING_DIALOG_CAPTION,
  115. ACPI_STR_SHUTDOWN_WARNING,
  116. MB_YESNO | MB_ICONWARNING) == IDNO) {
  117. // The user cancelled
  118. return S_FALSE;
  119. }
  120. //
  121. // Step 2: Prepare a safe configuration in case of errors.
  122. //
  123. // Make a backup copy of the old HAL
  124. // Get location of the system directory
  125. TCHAR* szSystemDir = new TCHAR[MAX_PATH+1];
  126. if (!szSystemDir) {
  127. // Out of memory
  128. DisplayGenericErrorAndUndoChanges();
  129. return S_FALSE;
  130. }
  131. UINT uiSysDirLen = GetSystemDirectory(szSystemDir, MAX_PATH+1);
  132. if (uiSysDirLen == 0) {
  133. // Some error occurred
  134. DisplayGenericErrorAndUndoChanges();
  135. if (szSystemDir) delete[] szSystemDir;
  136. return S_FALSE;
  137. }
  138. // Assemble strings with the locations of the current and backup file
  139. TCHAR szHal[] = TEXT("hal.dll");
  140. TCHAR* szHalCurrent = new TCHAR[uiSysDirLen + lstrlen(szHal) + 1];
  141. TCHAR* szHalBackup = new TCHAR[uiSysDirLen + lstrlen(g_HAL_BACKUP) + 1];
  142. if (!szHalCurrent || !szHalBackup) {
  143. // Out of memory
  144. DisplayGenericErrorAndUndoChanges();
  145. delete[] szSystemDir;
  146. if (szHalCurrent) delete[] szHalCurrent;
  147. if (szHalBackup) delete[] szHalBackup;
  148. return S_FALSE;
  149. }
  150. _tcscpy(szHalCurrent, szSystemDir);
  151. _tcscat(szHalCurrent, TEXT("\\"));
  152. _tcscat(szHalCurrent, szHal);
  153. _tcscpy(szHalBackup, szSystemDir);
  154. _tcscat(szHalBackup, TEXT("\\"));
  155. _tcscat(szHalBackup, g_HAL_BACKUP);
  156. // Copy the HAL
  157. if (CopyFile(szHalCurrent, szHalBackup, FALSE) == FALSE) {
  158. // Error copying file
  159. DisplayGenericErrorAndUndoChanges();
  160. delete[] szSystemDir;
  161. delete[] szHalCurrent;
  162. delete[] szHalBackup;
  163. return S_FALSE;
  164. }
  165. delete[] szSystemDir;
  166. delete[] szHalCurrent;
  167. delete[] szHalBackup;
  168. // Make it possible to boot with the backup HAL if necessary
  169. // Find the system partition letter
  170. // Edit boot.ini
  171. // -- add new NT5 boot line with "\HAL=hal-old.dll" on the end
  172. // Temporary: tell the user to do it manually
  173. MessageBox(NULL,
  174. TEXT("If you want to ensure that you can recover if this process fails,\nadd a line to your boot.ini with \" /HAL=hal-old.dll\""),
  175. TEXT("This is a temporary hack!"),
  176. MB_ICONWARNING | MB_OK);
  177. //
  178. // Step 3: Set up keyboard and mouse for use after reboot. This involves
  179. // removing them from the CriticalDeviceDatabase so that they will
  180. // be reconfigured (according to the new ACPI layout) after reboot.
  181. // The current keyboards and mice are in the CDD, but we must
  182. // populate it with all possibilities, because their HardwareIDs
  183. // will probably change once ACPI is enabled.
  184. //
  185. // Set up keyboard(s) for use after reboot
  186. if (RegDeleteDeviceKey(&GUID_DEVCLASS_KEYBOARD) == FALSE) {
  187. // Error
  188. DisplayGenericErrorAndUndoChanges();
  189. return S_FALSE;
  190. }
  191. // Set up mouse (mice) for use after reboot
  192. if (RegDeleteDeviceKey(&GUID_DEVCLASS_MOUSE) == FALSE) {
  193. // Error
  194. DisplayGenericErrorAndUndoChanges();
  195. return S_FALSE;
  196. }
  197. //
  198. // Step 4: Add new values to the registry:
  199. // - Add ACPI to the CriticalDeviceDatabase
  200. // - Add keyboards and mice to the CriticalDeviceDatabase
  201. // - Enable ACPI in the registry
  202. //
  203. if (InstallRegistryAndFilesUsingInf(g_ACPIENAB_INF,
  204. TEXT("ACPI_REGISTRY.Install")) == 0) {
  205. // Error
  206. DisplayGenericErrorAndUndoChanges();
  207. return S_FALSE;
  208. }
  209. //
  210. // Step 5: Copy the ACPI driver.
  211. //
  212. // Copy the ACPI driver to the system directory
  213. if (InstallRegistryAndFilesUsingInf(g_ACPIENAB_INF,
  214. TEXT("ACPI_DRIVER.Install")) == 0) {
  215. // Error
  216. DisplayGenericErrorAndUndoChanges();
  217. return S_FALSE;
  218. }
  219. //
  220. // Step 6: Copy the new HAL.
  221. //
  222. // Determine which HAL will be needed
  223. TCHAR szHalInstall[50];
  224. int HAL = 0;
  225. // Determine if it's a single or multi-processor machine
  226. BOOL SingleProc = (SystemInfo.dwNumberOfProcessors == 1);
  227. if (SingleProc) {
  228. HAL += 2;
  229. }
  230. // Determine if it's a PIC or APIC machine
  231. BOOL PIC = TRUE;
  232. if (!SingleProc) { // Don't run the UsePICHal function unless we have to
  233. PIC = FALSE;
  234. } else {
  235. if (UsePICHal(&PIC) == FALSE) {
  236. // An error occurred
  237. DisplayGenericErrorAndUndoChanges();
  238. return S_FALSE;
  239. }
  240. }
  241. if (PIC) {
  242. HAL += 1;
  243. }
  244. // Lookup table for HALs
  245. switch (HAL) {
  246. case 3: // x86 1-proc PIC
  247. _tcscpy(szHalInstall, TEXT("INTEL_1PROC_PIC_HAL"));
  248. break;
  249. case 2: // x86 1-proc APIC
  250. _tcscpy(szHalInstall, TEXT("INTEL_1PROC_APIC_HAL"));
  251. break;
  252. case 1: // x86 multi-proc PIC -- doesn't exist...
  253. _tcscpy(szHalInstall, TEXT("INTEL_MULTIPROC_PIC_HAL"));
  254. break;
  255. case 0: // x86 multi-proc APIC
  256. _tcscpy(szHalInstall, TEXT("INTEL_MULTIPROC_APIC_HAL"));
  257. break;
  258. }
  259. _tcscat(szHalInstall, TEXT(".Install"));
  260. // Copy the HAL to the system directory
  261. if (InstallRegistryAndFilesUsingInf(g_ACPIENAB_INF, szHalInstall) == 0) {
  262. // Error
  263. DisplayGenericErrorAndUndoChanges();
  264. return S_FALSE;
  265. }
  266. //
  267. // Step 7: Reboot.
  268. //
  269. // Warn the user that we're going to reboot
  270. DisplayDialogBox(ACPI_STR_REBOOT_DIALOG_CAPTION,
  271. ACPI_STR_REBOOT_WARNING,
  272. MB_OK);
  273. // Get shutdown privilege by opening the process token and adjusting its
  274. // privileges.
  275. HANDLE hToken;
  276. TOKEN_PRIVILEGES tkp;
  277. if (!OpenProcessToken(GetCurrentProcess(),
  278. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  279. &hToken)) {
  280. // Could not open process token. Tell the user to reboot manually.
  281. DisplayDialogBox(ACPI_STR_REBOOT_DIALOG_CAPTION,
  282. ACPI_STR_REBOOT_ERROR,
  283. MB_OK);
  284. return S_OK;
  285. }
  286. LookupPrivilegeValue(NULL,
  287. SE_SHUTDOWN_NAME,
  288. &tkp.Privileges[0].Luid);
  289. tkp.PrivilegeCount = 1;
  290. tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  291. AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
  292. // Reboot
  293. if (ExitWindowsEx(EWX_REBOOT | EWX_FORCEIFHUNG, 0) == 0) {
  294. // An error occurred. Tell the user to reboot manually.
  295. DisplayDialogBox(ACPI_STR_REBOOT_DIALOG_CAPTION,
  296. ACPI_STR_REBOOT_ERROR,
  297. MB_OK);
  298. }
  299. return S_OK;
  300. }
  301. //+---------------------------------------------------------------------------
  302. //
  303. // Function: InstallRegistryAndFilesUsingInf
  304. //
  305. // Purpose: Open an INF file and perform the registry addition/deletion and
  306. // file copy operations specified there under a given install
  307. // section.
  308. //
  309. // Arguments: szInfFileName [in] Name of INF file to open
  310. // (should be located in system inf
  311. // directory)
  312. // szInstallSection [in] Install section (in INF) to use
  313. //
  314. // Returns: TRUE if successful
  315. // FALSE otherwise
  316. //
  317. // Author: t-sdey 14 Aug 98
  318. //
  319. // Notes:
  320. //
  321. BOOL InstallRegistryAndFilesUsingInf(IN LPCTSTR szInfFileName,
  322. IN LPCTSTR szInstallSection)
  323. {
  324. HINF hinf;
  325. //
  326. // Prepare the file queue
  327. //
  328. // Create a file queue
  329. HSPFILEQ FileQueue = SetupOpenFileQueue();
  330. if(!FileQueue || (FileQueue == INVALID_HANDLE_VALUE)) {
  331. // Error
  332. return FALSE;
  333. }
  334. // Initialize the queue callback function
  335. HWND Window = NULL;
  336. VOID* DefaultContext = SetupInitDefaultQueueCallback(Window);
  337. //
  338. // Open the INF file and perform file installation
  339. //
  340. // Open the source INF
  341. hinf = SetupOpenInfFile(szInfFileName, TEXT("System"), INF_STYLE_WIN4, NULL);
  342. if (hinf == INVALID_HANDLE_VALUE) {
  343. // Error
  344. SetupCloseFileQueue(FileQueue);
  345. return FALSE;
  346. }
  347. // Append the layout INF to get the source location for the files
  348. if (SetupOpenAppendInfFile(g_LAYOUT_INF, hinf, NULL) == FALSE) {
  349. // Could not open file
  350. SetupCloseInfFile(hinf);
  351. SetupCloseFileQueue(FileQueue);
  352. return FALSE;
  353. }
  354. // Read the INF and perform the actions it dictates
  355. if (SetupInstallFromInfSection(NULL,
  356. hinf,
  357. szInstallSection,
  358. SPINST_REGISTRY | SPINST_FILES,
  359. HKEY_LOCAL_MACHINE,
  360. NULL, // Source root path
  361. SP_COPY_WARNIFSKIP,
  362. (PSP_FILE_CALLBACK)SetupDefaultQueueCallback,
  363. DefaultContext,
  364. NULL,
  365. NULL) == 0) {
  366. // Error
  367. SetupCloseInfFile(hinf);
  368. SetupCloseFileQueue(FileQueue);
  369. return FALSE;
  370. }
  371. // Commit the file queue to make sure all queued file copies are performed
  372. if (SetupCommitFileQueue(NULL,
  373. FileQueue,
  374. (PSP_FILE_CALLBACK)SetupDefaultQueueCallback,
  375. DefaultContext) == 0) {
  376. // Error
  377. SetupCloseInfFile(hinf);
  378. SetupCloseFileQueue(FileQueue);
  379. return FALSE;
  380. }
  381. // Clean up
  382. SetupCloseInfFile(hinf);
  383. SetupCloseFileQueue(FileQueue);
  384. return TRUE;
  385. }
  386. //+---------------------------------------------------------------------------
  387. //
  388. // Function: RegDeleteDeviceKey
  389. //
  390. // Purpose: All devices described by guid are removed from the device
  391. // tree (HKLM\SYSTEM\CurrentControlSet\Enum\Root).
  392. // This forces them to be reconfigured on reboot.
  393. //
  394. // Arguments: guid [in] GUID of device class
  395. //
  396. // Returns: TRUE if successful.
  397. // FALSE otherwise.
  398. //
  399. // Author: t-sdey 14 Aug 98
  400. //
  401. // Notes:
  402. //
  403. BOOL RegDeleteDeviceKey(IN const GUID* guid)
  404. {
  405. // Open the Root key under Enum with administrative access
  406. HKEY hkey = NULL;
  407. TCHAR szEnumRoot[] = TEXT("SYSTEM\\CurrentControlSet\\Enum\\Root");
  408. PSECURITY_DESCRIPTOR psdOriginal = NULL;
  409. if (DwRegOpenKeyExWithAdminAccess(HKEY_LOCAL_MACHINE,
  410. szEnumRoot,
  411. KEY_ALL_ACCESS,
  412. &hkey,
  413. &psdOriginal) != ERROR_SUCCESS) {
  414. // Error
  415. RegCloseKey(hkey);
  416. return FALSE;
  417. }
  418. // Get the list of devices with this GUID on the system. Remove each
  419. // of them from the device tree, so that the next time the computer boots
  420. // it is re-detected and re-configured for the new ACPI setup.
  421. // (Otherwise the device will be configured incorrectly.)
  422. // Get the list of devices with this GUID on the system
  423. HDEVINFO hdiDeviceClass = SetupDiGetClassDevs(guid, NULL, NULL, 0);
  424. // Prepare data structures for loop
  425. SP_DEVINFO_DATA DeviceInfoData;
  426. DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  427. DWORD dwIndex = 0;
  428. unsigned long BufferMax = 5000; // 5000 chars better be enough for the HID!
  429. unsigned long BufferLen;
  430. TCHAR* szHardwareID = new TCHAR[BufferMax];
  431. if (szHardwareID == NULL) {
  432. // Out of memory
  433. DisplayGenericErrorAndUndoChanges();
  434. SetupDiDestroyDeviceInfoList(hdiDeviceClass);
  435. if (psdOriginal) delete psdOriginal;
  436. RegCloseKey(hkey);
  437. return FALSE;
  438. }
  439. // Loop for each device with this GUID
  440. while (SetupDiEnumDeviceInfo(hdiDeviceClass, dwIndex, &DeviceInfoData)) {
  441. // Get the Hardware ID
  442. BufferLen = BufferMax;
  443. if (CM_Get_DevInst_Registry_Property_Ex(DeviceInfoData.DevInst,
  444. CM_DRP_HARDWAREID,
  445. NULL,
  446. szHardwareID,
  447. &BufferLen,
  448. 0,
  449. 0) != CR_SUCCESS) {
  450. // Error
  451. DisplayGenericErrorAndUndoChanges();
  452. SetupDiDestroyDeviceInfoList(hdiDeviceClass);
  453. if (szHardwareID) delete[] szHardwareID;
  454. if (psdOriginal) delete psdOriginal;
  455. RegCloseKey(hkey);
  456. return FALSE;
  457. }
  458. // Remove from the device tree
  459. if (RegDeleteKeyAndSubkeys(hkey, szHardwareID, TRUE) != ERROR_SUCCESS) {
  460. // Error
  461. DisplayGenericErrorAndUndoChanges();
  462. SetupDiDestroyDeviceInfoList(hdiDeviceClass);
  463. if (szHardwareID) delete[] szHardwareID;
  464. if (psdOriginal) delete psdOriginal;
  465. RegCloseKey(hkey);
  466. return FALSE;
  467. }
  468. dwIndex++;
  469. }
  470. // Reset the security on the Root key
  471. if (psdOriginal) {
  472. RegSetKeySecurity(hkey,
  473. (SECURITY_INFORMATION) (DACL_SECURITY_INFORMATION),
  474. psdOriginal);
  475. delete psdOriginal;
  476. }
  477. // Clean up
  478. SetupDiDestroyDeviceInfoList(hdiDeviceClass);
  479. if (szHardwareID)
  480. delete[] szHardwareID;
  481. if (hkey)
  482. RegCloseKey(hkey);
  483. return TRUE;
  484. }
  485. //+---------------------------------------------------------------------------
  486. //
  487. // Function: DisplayGenericErrorAndUndoChanges
  488. //
  489. // Purpose: Pop up a message box with a generic error message and then
  490. // undo as many changes as possible. Basically, used to recover
  491. // from errors which occur before ACPI is fully enabled.
  492. //
  493. // Arguments:
  494. //
  495. // Author: t-sdey 31 July 98
  496. //
  497. // Notes:
  498. //
  499. void DisplayGenericErrorAndUndoChanges()
  500. {
  501. // Give a generic error message
  502. DisplayDialogBox(ACPI_STR_ERROR_DIALOG_CAPTION,
  503. ACPI_STR_GENERAL_ERROR_MESSAGE,
  504. MB_OK | MB_ICONERROR);
  505. // Remove new entries from the CriticalDeviceDatabase
  506. InstallRegistryAndFilesUsingInf(g_ACPIENAB_INF,
  507. TEXT("ACPI_UNDO_CHANGES.Install"));
  508. }
  509. //+---------------------------------------------------------------------------
  510. //
  511. // Function: DisplayDialogBox
  512. //
  513. // Purpose: Display a popup informing the user of a warning or error.
  514. //
  515. // Arguments: dwCaptionID [in] the ID of the caption for the window
  516. // dwMessageID [in] the ID of the message to display
  517. // uiBoxType [in] the type of box to use
  518. //
  519. // Returns: integer flag, as would be returned by MessageBox
  520. //
  521. // Author: t-sdey 28 July 98
  522. //
  523. // Notes:
  524. //
  525. int DisplayDialogBox(IN DWORD dwCaptionID,
  526. IN DWORD dwMessageID,
  527. IN UINT uiBoxType)
  528. {
  529. // Prepare the strings
  530. TCHAR szCaption[512];
  531. TCHAR szMessage[5000];
  532. if(!LoadString(g_hinst, dwCaptionID, szCaption, 512)) {
  533. szCaption[0] = 0;
  534. }
  535. if(!LoadString(g_hinst, dwMessageID, szMessage, 5000)) {
  536. szMessage[0] = 0;
  537. }
  538. // Create the dialog box
  539. return (MessageBox(NULL, szMessage, szCaption, uiBoxType));
  540. }
  541. //+---------------------------------------------------------------------------
  542. //
  543. // Function: RegDeleteKeyAndSubkeys
  544. //
  545. // Purpose: (Recursively) Remove a registry key and all of its subkeys
  546. //
  547. // Arguments: hKey [in] Handle to an open registry key
  548. // lpszSubKey [in] Name of a subkey to be deleted along with all
  549. // of its subkeys
  550. // UseAdminAccess [in] Flag to indicate whether or not to try to
  551. // use administrative access
  552. //
  553. // Returns: ERROR_SUCCESS if entire subtree was successfully deleted.
  554. // ERROR_ACCESS_DENIED if given subkey could not be deleted.
  555. //
  556. // Author: t-sdey 15 July 98
  557. //
  558. // Notes: Modified from regedit.
  559. // This specifically does not attempt to deal rationally with the
  560. // case where the caller may not have access to some of the subkeys
  561. // of the key to be deleted. In this case, all the subkeys which
  562. // the caller can delete will be deleted, but the api will still
  563. // return ERROR_ACCESS_DENIED.
  564. //
  565. LONG RegDeleteKeyAndSubkeys(IN HKEY hKey,
  566. IN LPTSTR lpszSubKey,
  567. IN BOOL UseAdminAccess)
  568. {
  569. DWORD i;
  570. HKEY Key;
  571. LONG Status;
  572. DWORD dwStatus;
  573. DWORD ClassLength=0;
  574. DWORD SubKeys;
  575. DWORD MaxSubKey;
  576. DWORD MaxClass;
  577. DWORD Values;
  578. DWORD MaxValueName;
  579. DWORD MaxValueData;
  580. DWORD SecurityLength;
  581. FILETIME LastWriteTime;
  582. LPTSTR NameBuffer;
  583. PSECURITY_DESCRIPTOR psdOriginal = NULL; // used to remember security settings
  584. //
  585. // First open the given key so we can enumerate its subkeys
  586. //
  587. if (UseAdminAccess) {
  588. dwStatus = DwRegOpenKeyExWithAdminAccess(hKey,
  589. lpszSubKey,
  590. KEY_ALL_ACCESS,
  591. &Key,
  592. &psdOriginal);
  593. if (dwStatus == ERROR_SUCCESS) {
  594. Status = ERROR_SUCCESS;
  595. } else {
  596. Status = !(ERROR_SUCCESS); // It just has to be something else
  597. }
  598. } else {
  599. Status = RegOpenKeyEx(hKey,
  600. lpszSubKey,
  601. 0,
  602. KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
  603. &Key);
  604. }
  605. if (Status != ERROR_SUCCESS) {
  606. //
  607. // possibly we have delete access, but not enumerate/query.
  608. // So go ahead and try the delete call, but don't worry about
  609. // any subkeys. If we have any, the delete will fail anyway.
  610. //
  611. Status = RegDeleteKey(hKey, lpszSubKey);
  612. if (psdOriginal) {
  613. // Make sure to reset the subkey security -- probably a paranoid check
  614. RegSetKeySecurity(Key,
  615. (SECURITY_INFORMATION) (DACL_SECURITY_INFORMATION),
  616. psdOriginal);
  617. free(psdOriginal);
  618. }
  619. return(Status);
  620. }
  621. //
  622. // Use RegQueryInfoKey to determine how big to allocate the buffer
  623. // for the subkey names.
  624. //
  625. Status = RegQueryInfoKey(Key,
  626. NULL,
  627. &ClassLength,
  628. 0,
  629. &SubKeys,
  630. &MaxSubKey,
  631. &MaxClass,
  632. &Values,
  633. &MaxValueName,
  634. &MaxValueData,
  635. &SecurityLength,
  636. &LastWriteTime);
  637. if ((Status != ERROR_SUCCESS) &&
  638. (Status != ERROR_MORE_DATA) &&
  639. (Status != ERROR_INSUFFICIENT_BUFFER)) {
  640. // Make sure to reset the subkey security
  641. if (psdOriginal) {
  642. RegSetKeySecurity(Key,
  643. (SECURITY_INFORMATION) (DACL_SECURITY_INFORMATION),
  644. psdOriginal);
  645. free(psdOriginal);
  646. }
  647. RegCloseKey(Key);
  648. return(Status);
  649. }
  650. NameBuffer = (LPTSTR) LocalAlloc(LPTR, (MaxSubKey + 1)*sizeof(TCHAR));
  651. if (NameBuffer == NULL) {
  652. // Make sure to reset the subkey security
  653. if (psdOriginal) {
  654. RegSetKeySecurity(Key,
  655. (SECURITY_INFORMATION) (DACL_SECURITY_INFORMATION),
  656. psdOriginal);
  657. free(psdOriginal);
  658. }
  659. RegCloseKey(Key);
  660. return(ERROR_NOT_ENOUGH_MEMORY);
  661. }
  662. //
  663. // Enumerate subkeys and apply ourselves to each one.
  664. //
  665. i=0;
  666. do {
  667. Status = RegEnumKey(Key, i, NameBuffer, MaxSubKey+1);
  668. if (Status == ERROR_SUCCESS) {
  669. Status = RegDeleteKeyAndSubkeys(Key, NameBuffer, UseAdminAccess);
  670. }
  671. if (Status != ERROR_SUCCESS) {
  672. //
  673. // Failed to delete the key at the specified index. Increment
  674. // the index and keep going. We could probably bail out here,
  675. // since the api is going to fail, but we might as well keep
  676. // going and delete everything we can.
  677. //
  678. ++i;
  679. }
  680. } while ((Status != ERROR_NO_MORE_ITEMS) && (i < SubKeys));
  681. LocalFree((HLOCAL) NameBuffer);
  682. RegCloseKey(Key);
  683. // Delete the key
  684. Status = RegDeleteKey(hKey, lpszSubKey);
  685. if (psdOriginal)
  686. free(psdOriginal);
  687. return (Status);
  688. }
  689. //+---------------------------------------------------------------------------
  690. //
  691. // Function: IsAdministrator
  692. //
  693. // Purpose: Determine whether or not the current user has administrative
  694. // access to the system.
  695. //
  696. // Arguments:
  697. //
  698. // Returns: TRUE if the current user has administrative access
  699. // FALSE otherwise
  700. //
  701. // Author: t-sdey 17 Aug 98
  702. //
  703. // Notes: Copied from \nt\private\tapi\tomahawk\admin\setup\admin.c
  704. //
  705. BOOL IsAdministrator()
  706. {
  707. PTOKEN_GROUPS ptgGroups;
  708. DWORD dwSize, dwBufferSize;
  709. HANDLE hThread;
  710. HANDLE hAccessToken;
  711. PSID psidAdministrators;
  712. SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
  713. UINT x;
  714. BOOL bResult = FALSE;
  715. dwSize = 1000;
  716. ptgGroups = (PTOKEN_GROUPS)GlobalAlloc(GPTR, dwSize);
  717. hThread = GetCurrentProcess();
  718. if (!(OpenProcessToken(hThread,
  719. TOKEN_READ,
  720. &hAccessToken))) {
  721. CloseHandle(hThread);
  722. return FALSE;
  723. }
  724. dwBufferSize = 0;
  725. while (TRUE)
  726. {
  727. if (GetTokenInformation(hAccessToken,
  728. TokenGroups,
  729. (LPVOID)ptgGroups,
  730. dwSize,
  731. &dwBufferSize)) {
  732. break;
  733. }
  734. if (dwBufferSize > dwSize) {
  735. GlobalFree(ptgGroups);
  736. ptgGroups = (PTOKEN_GROUPS)GlobalAlloc(GPTR, dwBufferSize);
  737. dwSize = dwBufferSize;
  738. } else {
  739. CloseHandle(hThread);
  740. CloseHandle(hAccessToken);
  741. return FALSE;
  742. }
  743. }
  744. if ( !(AllocateAndInitializeSid(&siaNtAuthority,
  745. 2,
  746. SECURITY_BUILTIN_DOMAIN_RID,
  747. DOMAIN_ALIAS_RID_ADMINS,
  748. 0, 0, 0, 0, 0, 0,
  749. &psidAdministrators))) {
  750. CloseHandle(hThread);
  751. CloseHandle(hAccessToken);
  752. GlobalFree( ptgGroups );
  753. return FALSE;
  754. }
  755. for (x = 0; x < ptgGroups->GroupCount; x++) {
  756. if (EqualSid(psidAdministrators, ptgGroups->Groups[x].Sid)) {
  757. bResult = TRUE;
  758. break;
  759. }
  760. }
  761. FreeSid(psidAdministrators);
  762. CloseHandle(hAccessToken);
  763. CloseHandle(hThread);
  764. GlobalFree(ptgGroups);
  765. return bResult;
  766. }
  767. //+---------------------------------------------------------------------------
  768. //
  769. // Function: UsePICHal
  770. //
  771. // Purpose: Determine whether this is a PIC machine or not (not=APIC).
  772. //
  773. // Arguments: pPIC [out] A flag saying whether or not the machine is a PIC
  774. // machine. If it is (and there are no errors) then
  775. // pPIC will be set to TRUE. If it is an APIC machine
  776. // pPIC will be FALSE.
  777. //
  778. // Returns: TRUE if test was successful
  779. // FALSE if an error occurred
  780. //
  781. // Author: t-sdey 20 Aug 98
  782. //
  783. // Notes:
  784. //
  785. BOOL UsePICHal(IN BOOL* PIC)
  786. {
  787. *PIC = TRUE;
  788. // Find out which HAL was installed during setup by looking at
  789. // winnt\repair\setup.log.
  790. //
  791. // Determine the location of the setup log
  792. //
  793. // Determine the location of the windows directory
  794. TCHAR* szLogPath = new TCHAR[MAX_PATH+1];
  795. if (!szLogPath) {
  796. // Out of memory
  797. return FALSE;
  798. }
  799. if (GetWindowsDirectory(szLogPath, MAX_PATH+1) == 0) {
  800. // Some error occurred
  801. if (szLogPath) delete[] szLogPath;
  802. return FALSE;
  803. }
  804. // Complete the log path
  805. _tcscat(szLogPath, TEXT("\\repair\\setup.log"));
  806. //
  807. // Get the string describing the HAL that was used in setup
  808. //
  809. TCHAR szSetupHal[100];
  810. int numchars= GetPrivateProfileString(TEXT("Files.WinNt"),
  811. TEXT("\\WINNT\\system32\\hal.dll"),
  812. TEXT("DEFAULT"),
  813. szSetupHal,
  814. 100,
  815. szLogPath);
  816. if (numchars == 0) {
  817. // Could not get string
  818. if (szLogPath) delete[] szLogPath;
  819. return FALSE;
  820. }
  821. //
  822. // Determine if the APIC HAL was installed
  823. //
  824. // Test to see if the string is "halapic.dll"
  825. TCHAR szApicHal[] = TEXT("halapic.dll");
  826. szSetupHal[lstrlen(szApicHal)] = 0; // make sure it's null-terminated
  827. if (_tcsstr(szSetupHal, szApicHal) != NULL) {
  828. // They match... It's an APIC HAL
  829. *PIC = FALSE;
  830. }
  831. delete[] szLogPath;
  832. return TRUE;
  833. }