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.

2370 lines
65 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. setupasr.c
  5. Abstract:
  6. Services in this module implement the Automatic System Recovery (ASR)
  7. routines of guimode setup.
  8. Revision History:
  9. Initial Code Michael Peterson (v-michpe) 20.Jan.1998
  10. Code cleanup and changes Guhan Suriyanarayanan (guhans) 21.Sep.1999
  11. --*/
  12. #include "setupp.h"
  13. #pragma hdrstop
  14. #include <setupapi.h>
  15. #include <mountmgr.h>
  16. #include <accctrl.h>
  17. #include <aclapi.h>
  18. #define THIS_MODULE 'S'
  19. #include "asrpriv.h"
  20. ///////////////////////////////////////////////////////////////////////////////
  21. // Private Type and constant declarations
  22. ///////////////////////////////////////////////////////////////////////////////
  23. const PCWSTR AsrSifPath = L"%systemroot%\\repair\\asr.sif\0";
  24. const PCWSTR AsrCommandsSectionName = L"COMMANDS";
  25. const PCWSTR AsrCommandSuffix = L"/sifpath=%systemroot%\\repair\\asr.sif";
  26. const PCWSTR AsrTempDir = L"%systemdrive%\\TEMP";
  27. const PCWSTR AsrLogFileName = L"\\asr.log";
  28. const PCWSTR AsrErrorFileName = L"\\asr.err";
  29. const PCWSTR Asr_ControlAsrRegKey = L"SYSTEM\\CurrentControlSet\\Control\\ASR";
  30. const PCWSTR Asr_LastInstanceRegValue = L"Instance";
  31. //
  32. // The following are to update system and boot partition devices
  33. // in setup.log
  34. //
  35. const PCWSTR Asr_SystemDeviceEnvName = L"%ASR_C_SYSTEM_PARTITION_DEVICE%";
  36. const PCWSTR Asr_SystemDeviceWin32Path = L"\\\\?\\GLOBALROOT%ASR_C_SYSTEM_PARTITION_DEVICE%";
  37. const PCWSTR Asr_WinntDeviceEnvName = L"%ASR_C_WINNT_PARTITION_DEVICE%";
  38. const PCWSTR Asr_SetupLogFilePath = L"%systemroot%\\repair\\setup.log";
  39. const PCWSTR Asr_AsrLogFilePath = L"%systemroot%\\repair\\asr.log";
  40. const PCWSTR Asr_AsrErrorFilePath = L"%systemroot%\\repair\\asr.err";
  41. const PCWSTR Asr_OldAsrErrorFilePath = L"%systemroot%\\repair\\asr.err.old";
  42. const PCWSTR Asr_FatalErrorCommand = L"notepad.exe %systemroot%\\repair\\asr.err";
  43. ///////////////////////////////////////////////////////////////////////////////
  44. // Data global to this module
  45. ///////////////////////////////////////////////////////////////////////////////
  46. BOOL Gbl_IsAsrEnabled = FALSE;
  47. PWSTR Gbl_AsrErrorFilePath = NULL;
  48. PWSTR Gbl_AsrLogFilePath = NULL;
  49. HANDLE Gbl_AsrLogFileHandle = NULL;
  50. HANDLE Gbl_AsrSystemVolumeHandle = NULL;
  51. WCHAR g_szErrorMessage[4196];
  52. ///////////////////////////////////////////////////////////////////////////////
  53. // Macros
  54. ///////////////////////////////////////////////////////////////////////////////
  55. //
  56. // ASR Memory allocation and free wrappers
  57. //
  58. //
  59. // _AsrAlloc
  60. // Macro description:
  61. // ASSERTS first if ptr is non-NULL. The expectation is that
  62. // all ptrs must be initialised to NULL before they are allocated.
  63. // That way, we can catch instances where we try to re-allocate
  64. // memory without freeing first.
  65. //
  66. // IsNullFatal: flag to indicate if mem allocation failures are fatal
  67. //
  68. #define _AsrAlloc(ptr,sz,IsNullFatal) { \
  69. \
  70. if (ptr != NULL) { \
  71. AsrpPrintDbgMsg(_asrinfo, "Pointer being allocated not NULL.\r\n"); \
  72. MYASSERT(0); \
  73. } \
  74. \
  75. ptr = MyMalloc(sz); \
  76. \
  77. if (ptr) { \
  78. memset(ptr, 0, sz); \
  79. } \
  80. \
  81. if (!ptr) { \
  82. if ((BOOLEAN) IsNullFatal) { \
  83. AsrpPrintDbgMsg(_asrerror, "Setup was unable to allocate memory.\r\n"); \
  84. FatalError(MSG_LOG_OUTOFMEMORY, L"", 0, 0); \
  85. } \
  86. else { \
  87. AsrpPrintDbgMsg(_asrwarn, "Warning. Setup was unable to allocate memory.\r\n"); \
  88. } \
  89. } \
  90. }
  91. //
  92. // _AsrFree
  93. // Macro description:
  94. // Frees ptr and resets it to NULL.
  95. // Asserts if ptr was already NULL
  96. //
  97. #define _AsrFree(ptr) { \
  98. \
  99. if (NULL != ptr) { \
  100. MyFree(ptr); \
  101. ptr = NULL; \
  102. } \
  103. else { \
  104. AsrpPrintDbgMsg(_asrlog, "Attempt to free null Pointer.\r\n"); \
  105. MYASSERT(0); \
  106. } \
  107. }
  108. #define _AsrFreeIfNotNull(ptr) { \
  109. if (NULL != ptr) { \
  110. MyFree(ptr); \
  111. ptr = NULL; \
  112. } \
  113. }
  114. //
  115. // One ASR_RECOVERY_APP_NODE struct is created for each entry
  116. // in the [COMMANDS] section of asr.sif.
  117. //
  118. typedef struct _ASR_RECOVERY_APP_NODE {
  119. struct _ASR_RECOVERY_APP_NODE *Next;
  120. //
  121. // Expect this to always be 1
  122. //
  123. LONG SystemKey;
  124. //
  125. // The sequence number according to which the apps are run. If
  126. // two apps have the same sequence number, the app that appears
  127. // first in the sif file is run.
  128. //
  129. LONG SequenceNumber;
  130. //
  131. // The "actionOnCompletion" field for the app. If CriticalApp is
  132. // non-zero, and the app returns an non-zero exit-code, we shall
  133. // consider it a fatal failure and quit out of ASR.
  134. //
  135. LONG CriticalApp;
  136. //
  137. // The app to be launched
  138. //
  139. PWSTR RecoveryAppCommand;
  140. //
  141. // The paramaters for the app. This is just concatenated to the
  142. // string above. May be NULL.
  143. //
  144. PWSTR RecoveryAppParams;
  145. } ASR_RECOVERY_APP_NODE, *PASR_RECOVERY_APP_NODE;
  146. //
  147. // This contains our list of entries in the COMMANDS section,
  148. // sorted in order of sequence numbers.
  149. //
  150. typedef struct _ASR_RECOVERY_APP_LIST {
  151. PASR_RECOVERY_APP_NODE First; // Head
  152. PASR_RECOVERY_APP_NODE Last; // Tail
  153. LONG AppCount; // NumEntries
  154. } ASR_RECOVERY_APP_LIST, *PASR_RECOVERY_APP_LIST;
  155. //
  156. // We call this to change the boot.ini timeout value to 30 seconds
  157. //
  158. extern BOOL
  159. ChangeBootTimeout(IN UINT Timeout);
  160. //
  161. // From asr.c
  162. //
  163. extern BOOL
  164. AsrpRestoreNonCriticalDisksW(
  165. IN PCWSTR lpSifPath,
  166. IN BOOL bAllOrNothing
  167. );
  168. extern BOOL
  169. AsrpRestoreTimeZoneInformation(
  170. IN PCWSTR lpSifPath
  171. );
  172. //
  173. // Indices for fields in the [COMMANDS] section.
  174. //
  175. typedef enum _SIF_COMMANDS_FIELD_INDEX {
  176. ASR_SIF_COMMANDS_KEY = 0,
  177. ASR_SIF_SYSTEM_KEY, // Expected to always be "1"
  178. ASR_SIF_SEQUENCE_NUMBER,
  179. ASR_SIF_ACTION_ON_COMPLETION,
  180. ASR_SIF_COMMAND_STRING,
  181. ASR_SIF_COMMAND_PARAMETERS, // May be NULL
  182. SIF_SIF_NUMFIELDS // Must always be last
  183. } SIF_COMMANDS_FIELD_INDEX;
  184. #define _Asr_CHECK_BOOLEAN(b,msg) \
  185. if((b) == FALSE) { \
  186. AsrpFatalErrorExit(MSG_FATAL_ERROR, __LINE__, (msg)); \
  187. }
  188. ///////////////////////////////////////////////////////////////////////////////
  189. // Private Functions
  190. ///////////////////////////////////////////////////////////////////////////////
  191. //
  192. // Logs the message to the asr error file. Note that
  193. // AsrpInitialiseErrorFile must have been called once before
  194. // this routine is used.
  195. //
  196. VOID
  197. AsrpLogErrorMessage(
  198. IN PCWSTR buffer
  199. )
  200. {
  201. HANDLE hFile = NULL;
  202. DWORD bytesWritten = 0;
  203. if (Gbl_AsrErrorFilePath) {
  204. //
  205. // Open the error log
  206. //
  207. hFile = CreateFileW(
  208. Gbl_AsrErrorFilePath, // lpFileName
  209. GENERIC_WRITE | GENERIC_READ, // dwDesiredAccess
  210. FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode
  211. NULL, // lpSecurityAttributes
  212. OPEN_ALWAYS, // dwCreationFlags
  213. FILE_FLAG_WRITE_THROUGH, // dwFlagsAndAttributes
  214. NULL // hTemplateFile
  215. );
  216. if ((!hFile) || (INVALID_HANDLE_VALUE == hFile)) {
  217. return;
  218. }
  219. //
  220. // Move to the end of file
  221. //
  222. SetFilePointer(hFile, 0L, NULL, FILE_END);
  223. //
  224. // Add our error string
  225. //
  226. WriteFile(hFile,
  227. buffer,
  228. (wcslen(buffer) * sizeof(WCHAR)),
  229. &bytesWritten,
  230. NULL
  231. );
  232. //
  233. // And we're done
  234. //
  235. CloseHandle(hFile);
  236. }
  237. }
  238. //
  239. // Logs the message to the asr log file. Note that
  240. // AsrpInitialiseLogFile must have been called once before
  241. // this routine is used.
  242. //
  243. VOID
  244. AsrpLogMessage(
  245. IN CONST char Module,
  246. IN CONST ULONG Line,
  247. IN CONST ULONG MesgLevel,
  248. IN CONST PCSTR Message
  249. )
  250. {
  251. SYSTEMTIME currentTime;
  252. DWORD bytesWritten = 0;
  253. char buffer[4196];
  254. GetSystemTime(&currentTime);
  255. sprintf(buffer,
  256. "[%04hu/%02hu/%02hu %02hu:%02hu:%02hu.%03hu] %c%lu %s%s",
  257. currentTime.wYear,
  258. currentTime.wMonth,
  259. currentTime.wDay,
  260. currentTime.wHour,
  261. currentTime.wMinute,
  262. currentTime.wSecond,
  263. currentTime.wMilliseconds,
  264. Module,
  265. Line,
  266. ((DPFLTR_ERROR_LEVEL == MesgLevel) ? "(Error:ASR) " : (DPFLTR_WARNING_LEVEL == MesgLevel ? "(Warning:ASR) " : "")),
  267. Message
  268. );
  269. if (Gbl_AsrLogFileHandle) {
  270. WriteFile(Gbl_AsrLogFileHandle,
  271. buffer,
  272. (strlen(buffer) * sizeof(char)),
  273. &bytesWritten,
  274. NULL
  275. );
  276. }
  277. }
  278. VOID
  279. AsrpPrintDbgMsg(
  280. IN CONST char Module,
  281. IN CONST ULONG Line,
  282. IN CONST ULONG MesgLevel,
  283. IN PCSTR FormatString,
  284. ...)
  285. /*++
  286. Description:
  287. This prints a debug message AND makes the appropriate entries in
  288. the log and error files.
  289. Arguments:
  290. Line pass in __LINE__
  291. MesgLevel DPFLTR_ levels
  292. FormatString Formatted Message String to be printed.
  293. Returns:
  294. --*/
  295. {
  296. char str[4096]; // the message better fit in this
  297. va_list arglist;
  298. DbgPrintEx(DPFLTR_SETUP_ID, MesgLevel, "ASR %c%lu ", Module, Line);
  299. va_start(arglist, FormatString);
  300. wvsprintfA(str, FormatString, arglist);
  301. va_end(arglist);
  302. DbgPrintEx(DPFLTR_SETUP_ID, MesgLevel, str);
  303. if ((DPFLTR_ERROR_LEVEL == MesgLevel) ||
  304. (DPFLTR_WARNING_LEVEL == MesgLevel) ||
  305. (DPFLTR_TRACE_LEVEL == MesgLevel)
  306. ) {
  307. AsrpLogMessage(Module, Line, MesgLevel, str);
  308. }
  309. }
  310. //
  311. // This will terminate Setup and cause a reboot. This is called
  312. // on Out of Memory errors
  313. //
  314. VOID
  315. AsrpFatalErrorExit(
  316. IN LONG MsgValue,
  317. IN LONG LineNumber,
  318. IN PWSTR MessageString
  319. )
  320. {
  321. AsrpPrintDbgMsg(THIS_MODULE, LineNumber, DPFLTR_ERROR_LEVEL, "Fatal Error: %ws (%lu)",
  322. (MessageString ? MessageString : L"(No error string)"), GetLastError()
  323. );
  324. FatalError(MsgValue, MessageString, 0, 0);
  325. }
  326. //
  327. // This just adds the new node to the end of the list.
  328. // Note that this does NOT sort the list by sequenceNumber:
  329. // we'll do that later on
  330. //
  331. VOID
  332. AsrpAppendNodeToList(
  333. IN PASR_RECOVERY_APP_LIST pList,
  334. IN PASR_RECOVERY_APP_NODE pNode
  335. )
  336. {
  337. //
  338. // Insert at end of list.
  339. //
  340. pNode->Next = NULL;
  341. if (pList->AppCount == 0) {
  342. pList->First = pNode;
  343. } else {
  344. pList->Last->Next = pNode;
  345. }
  346. pList->Last = pNode;
  347. pList->AppCount += 1;
  348. }
  349. //
  350. // Pops off the first node in the list. The list is sorted
  351. // in order of increasing SequenceNumber's at this point.
  352. //
  353. PASR_RECOVERY_APP_NODE
  354. AsrpRemoveFirstNodeFromList(
  355. IN PASR_RECOVERY_APP_LIST pList
  356. )
  357. {
  358. PASR_RECOVERY_APP_NODE pNode;
  359. if(pList->AppCount == 0) {
  360. return NULL;
  361. }
  362. pNode = pList->First;
  363. pList->First = pNode->Next;
  364. pList->AppCount -= 1;
  365. MYASSERT(pList->AppCount >= 0);
  366. return pNode;
  367. }
  368. PWSTR // must be freed by caller
  369. AsrpExpandEnvStrings(
  370. IN CONST PCWSTR OriginalString
  371. )
  372. {
  373. PWSTR expandedString = NULL;
  374. UINT cchSize = MAX_PATH + 1, // start with a reasonable default
  375. cchRequiredSize = 0;
  376. BOOL result = FALSE;
  377. _AsrAlloc(expandedString, (cchSize * sizeof(WCHAR)), TRUE);
  378. cchRequiredSize = ExpandEnvironmentStringsW(OriginalString,
  379. expandedString,
  380. cchSize
  381. );
  382. if (cchRequiredSize > cchSize) {
  383. //
  384. // Buffer wasn't big enough; free and re-allocate as needed
  385. //
  386. _AsrFree(expandedString);
  387. cchSize = cchRequiredSize + 1;
  388. _AsrAlloc(expandedString, (cchSize * sizeof(WCHAR)), TRUE);
  389. cchRequiredSize = ExpandEnvironmentStringsW(OriginalString,
  390. expandedString,
  391. cchSize
  392. );
  393. }
  394. if ((0 == cchRequiredSize) || (cchRequiredSize > cchSize)) {
  395. //
  396. // Either the function failed, or the buffer wasn't big enough
  397. // even on the second try
  398. //
  399. _AsrFree(expandedString); // sets it to NULL
  400. }
  401. return expandedString;
  402. }
  403. //
  404. // Builds the invocation string, as the name suggests. It expands out
  405. // the environment variables that apps are allowed to use in the
  406. // sif file, and adds in /sifpath=<path to the sif file> at the end
  407. // of the command. So for an entry in the COMMANDS section of
  408. // the form:
  409. // 4=1,3500,0,"%TEMP%\app.exe","/param1 /param2"
  410. //
  411. // the invocation string would be of the form:
  412. // c:\windows\temp\app.exe /param1 /param2 /sifpath=c:\windows\repair\asr.sif
  413. //
  414. //
  415. PWSTR
  416. AsrpBuildInvocationString(
  417. IN PASR_RECOVERY_APP_NODE pNode // must not be NULL
  418. )
  419. {
  420. PWSTR app = pNode->RecoveryAppCommand,
  421. args = pNode->RecoveryAppParams,
  422. cmd = NULL,
  423. fullcmd = NULL;
  424. DWORD size = 0;
  425. MYASSERT(app);
  426. //
  427. // Build an command line that looks like...
  428. //
  429. // "%TEMP%\ntbackup recover /1 /sifpath=%systemroot%\repair\asr.sif"
  430. //
  431. // The /sifpath parameter is added to all apps being launched
  432. //
  433. //
  434. // Allocate memory for the cmd line
  435. //
  436. size = sizeof(WCHAR) *
  437. (
  438. wcslen(app) + // app name "%TEMP%\ntbackup"
  439. (args ? wcslen(args) : 0) + // arguments "recover /1"
  440. wcslen(AsrCommandSuffix) + // suffix "/sifpath=%systemroot%\repair\asr.sif"
  441. 4 // spaces and null
  442. );
  443. _AsrAlloc(cmd, size, TRUE); // won't return if alloc fails
  444. //
  445. // Build the string
  446. //
  447. swprintf(cmd,
  448. L"%ws %ws %ws",
  449. app,
  450. (args? args: L""),
  451. AsrCommandSuffix
  452. );
  453. //
  454. // Expand the %% stuff, to build the full path
  455. //
  456. fullcmd = AsrpExpandEnvStrings(cmd);
  457. _AsrFree(cmd);
  458. return fullcmd;
  459. }
  460. BOOL
  461. AsrpRetryIsServiceRunning(
  462. IN PWSTR ServiceName,
  463. IN UINT MaxRetries
  464. )
  465. {
  466. SERVICE_STATUS status;
  467. SC_HANDLE svcHandle = NULL, // handle to the service
  468. scmHandle = NULL; // handle to the service control manager
  469. UINT count = 0;
  470. BOOL errorsEncountered = FALSE;
  471. PWSTR errString = NULL;
  472. scmHandle = OpenSCManager(NULL, NULL, GENERIC_READ);
  473. if (!scmHandle) {
  474. //
  475. // OpenSCManager() call failed - we are broke.
  476. //
  477. AsrpPrintDbgMsg(_asrerror,
  478. "Setup was unable to open the service control manager. The error code returned was 0x%x.\r\n",
  479. GetLastError()
  480. );
  481. errString = MyLoadString(IDS_ASR_ERROR_UNABLE_TO_OPEN_SCM);
  482. if (errString) {
  483. swprintf(g_szErrorMessage, errString, GetLastError());
  484. AsrpLogErrorMessage(g_szErrorMessage);
  485. MyFree(errString);
  486. errString = NULL;
  487. }
  488. else {
  489. FatalError(MSG_LOG_OUTOFMEMORY, L"", 0, 0);
  490. }
  491. errorsEncountered = TRUE;
  492. goto EXIT;
  493. }
  494. svcHandle = OpenServiceW(scmHandle, ServiceName, SERVICE_QUERY_STATUS);
  495. if (!svcHandle) {
  496. //
  497. // OpenService() call failed - we are broke.
  498. //
  499. AsrpPrintDbgMsg(_asrerror,
  500. "Setup was unable to start the service \"%ws\". The error code returned was 0x%x.\r\n",
  501. ServiceName,
  502. GetLastError()
  503. );
  504. errString = MyLoadString(IDS_ASR_ERROR_UNABLE_TO_START_SERVICE);
  505. if (errString) {
  506. swprintf(g_szErrorMessage, errString, ServiceName, GetLastError());
  507. AsrpLogErrorMessage(g_szErrorMessage);
  508. MyFree(errString);
  509. errString = NULL;
  510. }
  511. else {
  512. FatalError(MSG_LOG_OUTOFMEMORY, L"", 0, 0);
  513. }
  514. errorsEncountered = TRUE;
  515. goto EXIT;
  516. }
  517. //
  518. // Got the service opened for query. See if it's running, and
  519. // if not, go thru the retry loop.
  520. //
  521. while (count < MaxRetries) {
  522. if (!QueryServiceStatus(svcHandle, &status)) {
  523. //
  524. // Couldn't query the status of the service
  525. //
  526. AsrpPrintDbgMsg(_asrerror,
  527. "Setup was unable to query the status of service \"%ws\". The error code returned was 0x%x\r\n",
  528. ServiceName,
  529. GetLastError()
  530. );
  531. errString = MyLoadString(IDS_ASR_ERROR_UNABLE_TO_START_SERVICE);
  532. if (errString) {
  533. swprintf(g_szErrorMessage, errString, ServiceName, GetLastError());
  534. AsrpLogErrorMessage(g_szErrorMessage);
  535. MyFree(errString);
  536. errString = NULL;
  537. }
  538. else {
  539. FatalError(MSG_LOG_OUTOFMEMORY, L"", 0, 0);
  540. }
  541. errorsEncountered = TRUE;
  542. goto EXIT;
  543. }
  544. if (status.dwCurrentState == SERVICE_RUNNING) {
  545. //
  546. // Service is running - we can proceed.
  547. //
  548. break;
  549. }
  550. ++count;
  551. AsrpPrintDbgMsg(_asrinfo,
  552. "Attempting to start service [%ws]: status = [%d], retry [%d]\r\n",
  553. ServiceName,
  554. status.dwCurrentState,
  555. count
  556. );
  557. Sleep(2000);
  558. }
  559. EXIT:
  560. if ((svcHandle) && (INVALID_HANDLE_VALUE != svcHandle)) {
  561. CloseServiceHandle(svcHandle);
  562. svcHandle = NULL;
  563. }
  564. if ((scmHandle) && (INVALID_HANDLE_VALUE != svcHandle)) {
  565. CloseServiceHandle(scmHandle);
  566. scmHandle = NULL;
  567. }
  568. if ((errorsEncountered) || (count >= MaxRetries)) {
  569. return FALSE;
  570. }
  571. else {
  572. return TRUE;
  573. }
  574. }
  575. //
  576. // Before launching apps, we need RSM (specifically, the backup app
  577. // might need RSM to access its backup media)
  578. //
  579. VOID
  580. AsrpStartNtmsService(VOID)
  581. {
  582. BOOL result = TRUE;
  583. DWORD exitCode = ERROR_SUCCESS;
  584. PWSTR registerNtmsCommand = NULL;
  585. AsrpPrintDbgMsg(_asrinfo, "Entered InitNtmsService()\r\n");
  586. //
  587. // RSM isn't setup to run during GUI mode setup, but the back-up app is
  588. // likely going to need access to tape-drives and other RSM devices.
  589. // So we regsvr32 the appropriate dll's and start the service
  590. //
  591. // Register the ntmssvc.dll using:
  592. // regsvr32 /s %Systemroot%\system32\ntmssvc.dll
  593. //
  594. result = FALSE;
  595. registerNtmsCommand = AsrpExpandEnvStrings(L"regsvr32 /s %systemroot%\\system32\\rsmps.dll");
  596. if (registerNtmsCommand) {
  597. result = InvokeExternalApplication(NULL, registerNtmsCommand, &exitCode);
  598. }
  599. _Asr_CHECK_BOOLEAN(result, L"regsvr32 /s %systemroot%\\rsmps.dll failed\r\n");
  600. AsrpPrintDbgMsg(_asrlog, "Executed [%ws]\r\n", registerNtmsCommand);
  601. _AsrFree(registerNtmsCommand);
  602. //
  603. // Register the ntmsapi.dll using:
  604. // regsvr32 /s %SystemRoot%\system32\ntmsapi.dll
  605. //
  606. result = FALSE;
  607. registerNtmsCommand = AsrpExpandEnvStrings(L"regsvr32 /s %systemroot%\\system32\\ntmssvc.dll");
  608. if (registerNtmsCommand) {
  609. result = InvokeExternalApplication(NULL, registerNtmsCommand, &exitCode);
  610. }
  611. _Asr_CHECK_BOOLEAN(result, L"regsvr32 /s %systemroot%\\ntmssvc.dll failed\r\n");
  612. AsrpPrintDbgMsg(_asrlog, "Executed [%ws]\r\n", registerNtmsCommand);
  613. _AsrFree(registerNtmsCommand);
  614. result = FALSE;
  615. registerNtmsCommand = AsrpExpandEnvStrings(L"%systemroot%\\system32\\rsmsink.exe /regserver");
  616. if (registerNtmsCommand) {
  617. result = InvokeExternalApplication(NULL, registerNtmsCommand, &exitCode);
  618. }
  619. _Asr_CHECK_BOOLEAN(result, L"%systemroot%\\system32\\rsmsink.exe /regserver failed\r\n");
  620. AsrpPrintDbgMsg(_asrlog, "Executed [%ws]\r\n", registerNtmsCommand);
  621. _AsrFree(registerNtmsCommand);
  622. //
  623. // Now, start the ntms service.
  624. //
  625. result = SetupStartService(L"ntmssvc", FALSE);
  626. _Asr_CHECK_BOOLEAN(result, L"Could not start RSM service (ntmssvc).\r\n");
  627. //
  628. // Check for ntms running, give a few retries.
  629. //
  630. result = AsrpRetryIsServiceRunning(L"ntmssvc", 30);
  631. _Asr_CHECK_BOOLEAN(result, L"Failed to start RSM service after 30 retries.\r\n");
  632. AsrpPrintDbgMsg(_asrinfo, "RSM service (ntmssvc) started.\r\n");
  633. }
  634. PWSTR
  635. AsrpReadField(
  636. PINFCONTEXT pInfContext,
  637. DWORD FieldIndex,
  638. BOOL NullOkay
  639. )
  640. {
  641. PWSTR data = NULL;
  642. UINT reqdSize = 0;
  643. BOOL result = FALSE;
  644. //
  645. // Allocate memory and read the data
  646. //
  647. _AsrAlloc(data, (sizeof(WCHAR) * (MAX_PATH + 1)), TRUE);
  648. result = SetupGetStringFieldW(
  649. pInfContext,
  650. FieldIndex,
  651. data,
  652. MAX_PATH + 1,
  653. &reqdSize
  654. );
  655. if (!result) {
  656. DWORD status = GetLastError();
  657. //
  658. // If our buffer was too small, allocate a larger buffer
  659. // and try again
  660. //
  661. if (ERROR_INSUFFICIENT_BUFFER == status) {
  662. status = ERROR_SUCCESS;
  663. _AsrFree(data);
  664. _AsrAlloc(data, (sizeof(WCHAR) * reqdSize), TRUE);
  665. result = SetupGetStringFieldW(
  666. pInfContext,
  667. FieldIndex,
  668. data,
  669. reqdSize,
  670. NULL // don't need required size any more
  671. );
  672. }
  673. }
  674. if (!result) {
  675. _AsrFree(data);
  676. _Asr_CHECK_BOOLEAN(NullOkay, L"Could not read entry from commands section");
  677. // Never returns if NullOkay is FALSE.
  678. // Memory leaks here then, since we don't free some structs. But
  679. // it's a fatal error, so the system must be rebooted anyway
  680. //
  681. }
  682. return data;
  683. }
  684. //
  685. // This adds in the "Instance" value under the ASR key.
  686. // Third party applications (or Windows components like DTC) can use
  687. // this to determine if a new ASR has been run since the last time we
  688. // booted, and can take any actions they need to. For instance, the
  689. // DTC log file needs to be recreated after an ASR, since it is not
  690. // backed-up or restored by the backup app, and Dtc refuses to start
  691. // if it doesn't find a log file when it expects one.
  692. //
  693. VOID
  694. AsrpAddRegistryEntry()
  695. {
  696. LONG result = 0;
  697. HKEY regKey = NULL;
  698. WCHAR szLastInstanceData[40];
  699. DWORD cbLastInstanceData = 0;
  700. SYSTEMTIME currentTime;
  701. GUID asrInstanceGuid;
  702. PWSTR lpGuidString = NULL;
  703. RPC_STATUS rpcStatus = RPC_S_OK;
  704. //
  705. // We try to set the key to a newly generated GUID, to make sure it is
  706. // unique (and different from the previous value stored there). If, for
  707. // some reason, we aren't able to generate a GUID, we'll just store the
  708. // current date and time as a string--that should be unique, too.
  709. //
  710. rpcStatus = UuidCreate(
  711. &asrInstanceGuid
  712. );
  713. if (RPC_S_OK == rpcStatus) {
  714. //
  715. // Convert the GUID to a printable string
  716. //
  717. rpcStatus = UuidToStringW(
  718. &asrInstanceGuid,
  719. &lpGuidString
  720. );
  721. if (RPC_S_OK == rpcStatus) {
  722. wsprintf(szLastInstanceData,
  723. L"%ws",
  724. lpGuidString
  725. );
  726. cbLastInstanceData = wcslen(szLastInstanceData)*sizeof(WCHAR);
  727. }
  728. if (lpGuidString) {
  729. RpcStringFreeW(&lpGuidString);
  730. }
  731. }
  732. if (RPC_S_OK != rpcStatus) {
  733. //
  734. // We couldn't get a GUID. Let's store the time-stamp ...
  735. //
  736. GetSystemTime(&currentTime);
  737. wsprintf(szLastInstanceData,
  738. L"%04hu%02hu%02hu%02hu%02hu%02hu%03hu",
  739. currentTime.wYear,
  740. currentTime.wMonth,
  741. currentTime.wDay,
  742. currentTime.wHour,
  743. currentTime.wMinute,
  744. currentTime.wSecond,
  745. currentTime.wMilliseconds
  746. );
  747. cbLastInstanceData = wcslen(szLastInstanceData)*sizeof(WCHAR);
  748. }
  749. result = RegCreateKeyExW(
  750. HKEY_LOCAL_MACHINE, // hKey
  751. Asr_ControlAsrRegKey, // lpSubKey
  752. 0, // reserved
  753. NULL, // lpClass
  754. REG_OPTION_NON_VOLATILE, // dwOptions
  755. MAXIMUM_ALLOWED, // samDesired
  756. NULL, // lpSecurityAttributes
  757. &regKey, // phkResult
  758. NULL // lpdwDisposition
  759. );
  760. if ((ERROR_SUCCESS != result) || (!regKey)) {
  761. AsrpPrintDbgMsg(_asrwarn,
  762. "Could not create the Control\\ASR registry entry (0x%x).\r\n",
  763. result
  764. );
  765. return;
  766. }
  767. result = RegSetValueExW(
  768. regKey, // hKey
  769. Asr_LastInstanceRegValue, // lpValueName
  770. 0L, // reserved
  771. REG_SZ, // dwType
  772. (LPBYTE)szLastInstanceData, // lpData
  773. cbLastInstanceData // cbData
  774. );
  775. RegCloseKey(regKey);
  776. if (ERROR_SUCCESS != result) {
  777. AsrpPrintDbgMsg(_asrwarn,
  778. "Could not set the ASR instance-ID in the registry (0x%x).\r\n",
  779. result
  780. );
  781. return;
  782. }
  783. AsrpPrintDbgMsg(_asrlog,
  784. "Set the ASR instance-ID at [%ws\\%ws] value to [%ws]\r\n",
  785. Asr_ControlAsrRegKey,
  786. Asr_LastInstanceRegValue,
  787. szLastInstanceData
  788. );
  789. }
  790. VOID
  791. AsrpSetEnvironmentVariables()
  792. {
  793. PWSTR TempPath = AsrpExpandEnvStrings(AsrTempDir);
  794. if (!CreateDirectoryW(TempPath, NULL)) {
  795. AsrpPrintDbgMsg(_asrwarn,
  796. "Unable to create TEMP directory [%ws] (%lu)\r\n",
  797. TempPath, GetLastError()
  798. );
  799. }
  800. AsrpPrintDbgMsg(_asrlog,
  801. "Setting environment variables TEMP and TMP to [%ws]\r\n",
  802. TempPath
  803. );
  804. if (!SetEnvironmentVariableW(L"TEMP", TempPath)) {
  805. AsrpPrintDbgMsg(_asrwarn,
  806. "Unable to set environment variable TEMP to [%ws] (%lu)\r\n",
  807. TempPath, GetLastError()
  808. );
  809. }
  810. if (!SetEnvironmentVariableW(L"TMP", TempPath)) {
  811. AsrpPrintDbgMsg(_asrwarn,
  812. "Unable to set environment variable TEMP to [%ws] (%lu)\r\n",
  813. TempPath, GetLastError()
  814. );
  815. }
  816. _AsrFree(TempPath);
  817. return;
  818. }
  819. VOID
  820. AsrpInitExecutionEnv(
  821. OUT PASR_RECOVERY_APP_LIST List
  822. )
  823. {
  824. PWSTR stateFileName = NULL;
  825. HINF sifHandle = NULL;
  826. LONG lineCount = 0,
  827. line = 0;
  828. BOOL result = FALSE;
  829. INFCONTEXT infContext;
  830. //
  831. // Start the RSM service
  832. //
  833. AsrpStartNtmsService();
  834. //
  835. // Open the asr.sif file and build the list
  836. // of commands to be launched.
  837. //
  838. stateFileName = AsrpExpandEnvStrings(AsrSifPath);
  839. if (!stateFileName) {
  840. AsrpPrintDbgMsg(_asrerror, "Setup was unable to locate the ASR state file asr.sif on this machine.\r\n");
  841. FatalError(MSG_LOG_SYSINFBAD, L"asr.sif",0,0);
  842. }
  843. sifHandle = SetupOpenInfFileW(
  844. stateFileName,
  845. NULL, // Inf Class
  846. INF_STYLE_WIN4,
  847. NULL // Error-line
  848. );
  849. if ((!sifHandle) || (INVALID_HANDLE_VALUE == sifHandle)) {
  850. AsrpPrintDbgMsg(_asrerror,
  851. "Setup was unable to process the ASR state file %ws (0x%x). This could indicate that the file is corrupt, or has been modified since the last ASR backup.\r\n",
  852. stateFileName,
  853. GetLastError());
  854. _AsrFree(stateFileName);
  855. FatalError(MSG_LOG_SYSINFBAD, L"asr.sif",0,0);
  856. }
  857. _AsrFree(stateFileName);
  858. //
  859. // Read the COMMANDS section, and add each command to our list
  860. //
  861. lineCount = SetupGetLineCountW(sifHandle, AsrCommandsSectionName);
  862. for (line = 0; line < lineCount; line++) {
  863. //
  864. // Create a new node
  865. //
  866. PASR_RECOVERY_APP_NODE pNode = NULL;
  867. _AsrAlloc(pNode, (sizeof(ASR_RECOVERY_APP_NODE)), TRUE);
  868. //
  869. // Get the inf context for the line in asr.sif. This will be used
  870. // to read the fields on that line
  871. //
  872. result = SetupGetLineByIndexW(
  873. sifHandle,
  874. AsrCommandsSectionName,
  875. line,
  876. &infContext
  877. );
  878. _Asr_CHECK_BOOLEAN(result, L"SetupGetLinebyIndex failed");
  879. //
  880. // Read in the int fields
  881. //
  882. result = SetupGetIntField(
  883. &infContext,
  884. ASR_SIF_SYSTEM_KEY,
  885. &(pNode->SystemKey)
  886. );
  887. _Asr_CHECK_BOOLEAN(result, L"could not get system key in commands section");
  888. result = SetupGetIntField(
  889. &infContext,
  890. ASR_SIF_SEQUENCE_NUMBER,
  891. &(pNode->SequenceNumber)
  892. );
  893. _Asr_CHECK_BOOLEAN(result, L"could not get sequence number in commands section");
  894. result = SetupGetIntField(
  895. &infContext,
  896. ASR_SIF_ACTION_ON_COMPLETION,
  897. &(pNode->CriticalApp)
  898. );
  899. _Asr_CHECK_BOOLEAN(result, L"could not get criticalApp in commands section");
  900. //
  901. // Read in the string fields
  902. //
  903. pNode->RecoveryAppCommand = AsrpReadField(
  904. &infContext,
  905. ASR_SIF_COMMAND_STRING,
  906. FALSE // Null not okay
  907. );
  908. pNode->RecoveryAppParams = AsrpReadField(
  909. &infContext,
  910. ASR_SIF_COMMAND_PARAMETERS,
  911. TRUE // Null okay
  912. );
  913. //
  914. // Add this node to our list, and move on to next
  915. //
  916. AsrpAppendNodeToList(List, pNode);
  917. }
  918. SetupCloseInfFile(sifHandle);
  919. }
  920. //
  921. // Bubble sort ...
  922. //
  923. VOID
  924. AsrpSortAppListBySequenceNumber(PASR_RECOVERY_APP_LIST pList)
  925. {
  926. PASR_RECOVERY_APP_NODE
  927. pCurr = NULL,
  928. pNext = NULL,
  929. *ppPrev = NULL;
  930. BOOLEAN done = FALSE;
  931. if ((!pList) || (!pList->First)) {
  932. MYASSERT(0 && L"Recovery App List pList is NULL");
  933. return;
  934. }
  935. //
  936. // Start the outer loop. Each iteration of the outer loop includes a
  937. // full pass down the list, and runs until the inner loop is satisfied
  938. // that no more passes are needed.
  939. //
  940. while (!done) {
  941. //
  942. // Start at the beginning of the list for each inner (node) loop.
  943. //
  944. // We will initialize a pointer *to the pointer* which points to
  945. // the current node - this pointer might be the address of the "list
  946. // first" pointer (as it always will be at the start of an inner loop),
  947. // or as the inner loop progresses, it might be the address of the
  948. // "next" pointer in the previous node. In either case, the pointer
  949. // to which ppPrev points will be changed in the event of a node swap.
  950. //
  951. pCurr = pList->First;
  952. ppPrev = &(pList->First);
  953. done = TRUE;
  954. MYASSERT(pCurr);
  955. while (TRUE) {
  956. pNext = pCurr->Next;
  957. //
  958. // If the current node is the last one, reset to the beginning
  959. // and break out to start a new inner loop.
  960. //
  961. if (pNext == NULL) {
  962. pCurr = pList->First;
  963. break;
  964. }
  965. //
  966. // If the node *after* the current node has a lower sequence
  967. // number, fix up the pointers to swap the two nodes.
  968. //
  969. if (pCurr->SequenceNumber > pNext->SequenceNumber) {
  970. done = FALSE;
  971. pCurr->Next = pNext->Next;
  972. pNext->Next = pCurr;
  973. *ppPrev = pNext;
  974. ppPrev = &(pNext->Next);
  975. }
  976. else {
  977. ppPrev = &(pCurr->Next);
  978. pCurr = pCurr->Next;
  979. }
  980. }
  981. }
  982. }
  983. VOID
  984. AsrpPerformSifIntegrityCheck(IN HINF Handle)
  985. {
  986. //
  987. // No check for now.
  988. //
  989. return;
  990. }
  991. //
  992. // This checks if the following entries are different in setup.log
  993. // from their values. This could happen because we might have installed
  994. // to a new disk that has a different disk number
  995. //
  996. // [Paths]
  997. // TargetDevice = "\Device\Harddisk0\Partition2"
  998. // SystemPartition = "\Device\Harddisk0\Partition1"
  999. //
  1000. // If they are different, we'll update them.
  1001. //
  1002. BOOL
  1003. AsrpCheckSetupLogDeviceEntries(
  1004. PWSTR CurrentSystemDevice, // used for SystemPartition
  1005. PWSTR CurrentBootDevice, // used for TargetDevice
  1006. PWSTR LogFileName // path to setup.log
  1007. )
  1008. {
  1009. WCHAR szLine[MAX_INF_STRING_LENGTH + 1];
  1010. PWSTR lpLine = NULL;
  1011. BOOL isDifferent = FALSE;
  1012. FILE *fp = NULL;
  1013. INT iNumEntries = 0;
  1014. //
  1015. // Open existing setup.log
  1016. //
  1017. fp = _wfopen(LogFileName, L"r");
  1018. if (!fp) {
  1019. AsrpPrintDbgMsg(_asrwarn,
  1020. "Could not open setup log file [%ws]\r\n",
  1021. LogFileName
  1022. );
  1023. return FALSE;
  1024. }
  1025. //
  1026. // Check each line of the file for the System or Boot device entries
  1027. //
  1028. lpLine = fgetws(szLine, MAX_PATH-1, fp);
  1029. while ((lpLine) && (iNumEntries < 2)) {
  1030. BOOL systemEntry = FALSE;
  1031. BOOL bootEntry = FALSE;
  1032. if (wcsstr(szLine, L"SystemPartition =")) {
  1033. systemEntry = TRUE;
  1034. iNumEntries++;
  1035. }
  1036. if (wcsstr(szLine, L"TargetDevice =")) {
  1037. bootEntry = TRUE;
  1038. iNumEntries++;
  1039. }
  1040. if (systemEntry || bootEntry) {
  1041. PWSTR DeviceName = NULL;
  1042. //
  1043. // Both the system and boot entries must have the full
  1044. // devicepath in them, of the form \Device\Harddisk0\Partition1
  1045. //
  1046. DeviceName = wcsstr(szLine, L"\\Device");
  1047. if (!DeviceName) {
  1048. isDifferent = TRUE;
  1049. AsrpPrintDbgMsg(_asrlog,
  1050. "Marking setup logs different: \\Device\\ not found in boot or system entry\r\n"
  1051. );
  1052. break;
  1053. }
  1054. else {
  1055. //
  1056. // Find the start of the "Hardisk0\Partition1" text after \Device
  1057. //
  1058. PWSTR ss = wcsstr(DeviceName, L"\"");
  1059. if (!ss) {
  1060. isDifferent = TRUE;
  1061. AsrpPrintDbgMsg(_asrlog,
  1062. "Marking setup logs different: \\Device\\ not found in boot or system entry\r\n"
  1063. );
  1064. break;
  1065. }
  1066. else {
  1067. ss[0] = L'\0';
  1068. }
  1069. }
  1070. //
  1071. // And check if this device matches
  1072. //
  1073. if (systemEntry) {
  1074. AsrpPrintDbgMsg(_asrinfo,
  1075. "Comparing System Device. Current:[%ws] setup.log:[%ws]\r\n",
  1076. CurrentSystemDevice,
  1077. DeviceName
  1078. );
  1079. if (wcscmp(DeviceName, CurrentSystemDevice) != 0) {
  1080. isDifferent = TRUE;
  1081. AsrpPrintDbgMsg(_asrlog,
  1082. "System Device has changed. Current:[%ws] setup.log:[%ws]\r\n",
  1083. CurrentSystemDevice,
  1084. DeviceName
  1085. );
  1086. break;
  1087. }
  1088. }
  1089. else if (bootEntry) {
  1090. AsrpPrintDbgMsg(_asrinfo,
  1091. "Comparing Boot Device. Current:[%ws] setup.log:[%ws]\r\n",
  1092. CurrentBootDevice,
  1093. DeviceName
  1094. );
  1095. if (wcscmp(DeviceName, CurrentBootDevice) != 0) {
  1096. isDifferent = TRUE;
  1097. AsrpPrintDbgMsg(_asrlog,
  1098. "Boot device has changed. Current:[%ws] setup.log:[%ws]\r\n",
  1099. CurrentBootDevice,
  1100. DeviceName
  1101. );
  1102. break;
  1103. }
  1104. }
  1105. }
  1106. lpLine = fgetws(szLine, MAX_PATH-1, fp);
  1107. }
  1108. if (!isDifferent) {
  1109. AsrpPrintDbgMsg(_asrinfo, "No changes in system and boot devices for setup.log\r\n");
  1110. }
  1111. fclose(fp);
  1112. fp = NULL;
  1113. return isDifferent;
  1114. }
  1115. //
  1116. // If the setup.log restored by the backup from tape has a different
  1117. // boot or system device marked (we might have picked a new disk in
  1118. // textmode Setup), this will update the relevant entries to match the
  1119. // current boot and system devices.
  1120. //
  1121. VOID
  1122. AsrpMergeSetupLog(
  1123. PWSTR CurrentSystemDevice,
  1124. PWSTR CurrentBootDevice,
  1125. PWSTR LogFileName
  1126. )
  1127. {
  1128. WCHAR szLine[MAX_INF_STRING_LENGTH + 1];
  1129. PWSTR lpLine = NULL,
  1130. lpOldFileName = NULL,
  1131. lpNewFileName = NULL;
  1132. BOOL result = FALSE;
  1133. FILE *fpNew = NULL,
  1134. *fpCurrent = NULL;
  1135. INT iNumEntries = 0;
  1136. //
  1137. // Create the "new" and "old" file names, i.e., "setup.log.new" and "setup.log.old"
  1138. //
  1139. _AsrAlloc(lpNewFileName, ((wcslen(LogFileName) + 5) * sizeof(WCHAR)), TRUE)
  1140. wcscpy(lpNewFileName, LogFileName);
  1141. wcscat(lpNewFileName, L".new");
  1142. _AsrAlloc(lpOldFileName, ((wcslen(LogFileName) + 5) * sizeof(WCHAR)), TRUE);
  1143. wcscpy(lpOldFileName, LogFileName);
  1144. wcscat(lpOldFileName, L".old");
  1145. //
  1146. // Open the current setup.log file.
  1147. //
  1148. fpCurrent = _wfopen(LogFileName, L"r");
  1149. if (!fpCurrent) {
  1150. AsrpPrintDbgMsg(_asrwarn, "Setup was unable to open the setup log file \"%ws\"\r\n", LogFileName);
  1151. goto EXIT;
  1152. }
  1153. //
  1154. // Open the new file - we will write into this one.
  1155. //
  1156. fpNew = _wfopen(lpNewFileName, L"w");
  1157. if (!fpNew) {
  1158. AsrpPrintDbgMsg(_asrwarn, "Setup was unable to open the setup log file \"%ws\"\r\n", lpNewFileName);
  1159. goto EXIT;
  1160. }
  1161. //
  1162. // Read each line in the log file, copy into the new file, unless we hit
  1163. // one of the two lines in question. Once we've seen both of them, don't
  1164. // check for them anymore.
  1165. //
  1166. lpLine = fgetws(szLine, MAX_INF_STRING_LENGTH, fpCurrent);
  1167. while (lpLine) {
  1168. BOOL systemEntry = FALSE;
  1169. BOOL bootEntry = FALSE;
  1170. //
  1171. // If we've already found both entries of interest, just copy
  1172. // and continue.
  1173. //
  1174. if (iNumEntries >= 2) {
  1175. fputws(szLine, fpNew);
  1176. lpLine = fgetws(szLine, MAX_INF_STRING_LENGTH, fpCurrent);
  1177. continue;
  1178. }
  1179. //
  1180. // Is this line either the boot or system device?
  1181. //
  1182. if (wcsstr(szLine, L"SystemPartition =")) {
  1183. AsrpPrintDbgMsg(_asrlog,
  1184. "Changing SystemPartition in setup.log to %ws\r\n",
  1185. CurrentSystemDevice
  1186. );
  1187. ++iNumEntries;
  1188. wcscpy(szLine, L"SystemPartition = \"");
  1189. wcscat(szLine, CurrentSystemDevice);
  1190. wcscat(szLine, L"\"\n");
  1191. }
  1192. else if (wcsstr(szLine, L"TargetDevice =")) {
  1193. AsrpPrintDbgMsg(_asrlog,
  1194. "Changing TargetDevice in setup.log to %ws\r\n",
  1195. CurrentBootDevice
  1196. );
  1197. ++iNumEntries;
  1198. wcscpy(szLine, L"TargetDevice = \"");
  1199. wcscat(szLine, CurrentBootDevice);
  1200. wcscat(szLine, L"\"\n");
  1201. }
  1202. fputws(szLine, fpNew);
  1203. lpLine = fgetws(szLine, MAX_INF_STRING_LENGTH, fpCurrent);
  1204. }
  1205. //
  1206. // Rename the current setup.log to setup.log.old, and setup.log.new to
  1207. // setup.log. Need to delay this until reboot since setup.log is in
  1208. // use.
  1209. //
  1210. result = MoveFileExW(LogFileName,
  1211. lpOldFileName,
  1212. MOVEFILE_REPLACE_EXISTING | MOVEFILE_DELAY_UNTIL_REBOOT
  1213. );
  1214. if (!result) {
  1215. AsrpPrintDbgMsg(_asrwarn,
  1216. "MoveFileEx([%ws] to [%ws]) failed (%lu)",
  1217. LogFileName, lpOldFileName, GetLastError()
  1218. );
  1219. }
  1220. else {
  1221. result = MoveFileExW(lpNewFileName,
  1222. LogFileName,
  1223. MOVEFILE_REPLACE_EXISTING | MOVEFILE_DELAY_UNTIL_REBOOT
  1224. );
  1225. if (!result) {
  1226. AsrpPrintDbgMsg(_asrwarn,
  1227. "MoveFileEx([%ws] to [%ws]) failed (%lu)",
  1228. lpNewFileName, LogFileName, GetLastError()
  1229. );
  1230. }
  1231. }
  1232. EXIT:
  1233. if (fpCurrent) {
  1234. fclose(fpCurrent);
  1235. fpCurrent = NULL;
  1236. }
  1237. if (fpNew) {
  1238. fclose(fpNew);
  1239. fpNew = NULL;
  1240. }
  1241. _AsrFree(lpNewFileName);
  1242. _AsrFree(lpOldFileName);
  1243. }
  1244. VOID
  1245. AsrpMergeSetupLogIfNeeded()
  1246. {
  1247. PWSTR currentSystemDevice = NULL,
  1248. currentBootDevice = NULL,
  1249. winntRootDir = NULL,
  1250. setupLogFileName = NULL;
  1251. BOOL isSetupLogDifferent = FALSE;
  1252. //
  1253. // Get the environment variable for the partition devices
  1254. //
  1255. currentSystemDevice = AsrpExpandEnvStrings(Asr_SystemDeviceEnvName);
  1256. currentBootDevice = AsrpExpandEnvStrings(Asr_WinntDeviceEnvName);
  1257. setupLogFileName = AsrpExpandEnvStrings(Asr_SetupLogFilePath);
  1258. if ((!currentSystemDevice) ||
  1259. (!currentBootDevice) ||
  1260. (!setupLogFileName)) {
  1261. goto EXIT;
  1262. }
  1263. //
  1264. // Check if the system and/or boot devices listed in setup.log are
  1265. // different than the current devices
  1266. //
  1267. isSetupLogDifferent = AsrpCheckSetupLogDeviceEntries(
  1268. currentSystemDevice,
  1269. currentBootDevice,
  1270. setupLogFileName
  1271. );
  1272. if (isSetupLogDifferent) {
  1273. //
  1274. // They are different: fix it.
  1275. //
  1276. AsrpMergeSetupLog(currentSystemDevice,
  1277. currentBootDevice,
  1278. setupLogFileName
  1279. );
  1280. }
  1281. EXIT:
  1282. _AsrFreeIfNotNull(setupLogFileName);
  1283. _AsrFreeIfNotNull(currentBootDevice);
  1284. _AsrFreeIfNotNull(currentSystemDevice);
  1285. }
  1286. BOOL
  1287. AsrpConstructSecurityAttributes(
  1288. IN OUT LPSECURITY_ATTRIBUTES psaSecurityAttributes
  1289. )
  1290. {
  1291. BOOL bResult = FALSE;
  1292. DWORD dwStatus = ERROR_SUCCESS;
  1293. PSID psidBackupOperators = NULL;
  1294. PSID psidAdministrators = NULL;
  1295. PACL paclDiscretionaryAcl = NULL;
  1296. SID_IDENTIFIER_AUTHORITY sidNtAuthority = SECURITY_NT_AUTHORITY;
  1297. EXPLICIT_ACCESS eaExplicitAccess[2];
  1298. //
  1299. // Initialise the security descriptor.
  1300. //
  1301. bResult = InitializeSecurityDescriptor(
  1302. psaSecurityAttributes->lpSecurityDescriptor,
  1303. SECURITY_DESCRIPTOR_REVISION
  1304. );
  1305. _AsrpErrExitCode((!bResult), dwStatus, GetLastError());
  1306. //
  1307. // Create a SID for the Backup Operators group.
  1308. //
  1309. bResult = AllocateAndInitializeSid(&sidNtAuthority,
  1310. 2,
  1311. SECURITY_BUILTIN_DOMAIN_RID, //SECURITY_LOCAL_SYSTEM_RID,
  1312. DOMAIN_ALIAS_RID_BACKUP_OPS,
  1313. 0, 0, 0, 0, 0, 0,
  1314. &psidBackupOperators
  1315. );
  1316. _AsrpErrExitCode((!bResult), dwStatus, GetLastError());
  1317. //
  1318. // Create a SID for the Administrators group.
  1319. //
  1320. bResult = AllocateAndInitializeSid (&sidNtAuthority,
  1321. 2,
  1322. SECURITY_BUILTIN_DOMAIN_RID,
  1323. DOMAIN_ALIAS_RID_ADMINS,
  1324. 0, 0, 0, 0, 0, 0,
  1325. &psidAdministrators
  1326. );
  1327. _AsrpErrExitCode((!bResult), dwStatus, GetLastError());
  1328. //
  1329. // Initialize the array of EXPLICIT_ACCESS structures for an
  1330. // ACEs we are setting.
  1331. //
  1332. // The first ACE allows the Backup Operators group full access
  1333. // and the second, allowa the Administrators group full
  1334. // access.
  1335. //
  1336. eaExplicitAccess[0].grfAccessPermissions = FILE_ALL_ACCESS;
  1337. eaExplicitAccess[0].grfAccessMode = SET_ACCESS;
  1338. eaExplicitAccess[0].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  1339. eaExplicitAccess[0].Trustee.pMultipleTrustee = NULL;
  1340. eaExplicitAccess[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  1341. eaExplicitAccess[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  1342. eaExplicitAccess[0].Trustee.TrusteeType = TRUSTEE_IS_ALIAS;
  1343. eaExplicitAccess[0].Trustee.ptstrName = (LPTSTR) psidAdministrators;
  1344. eaExplicitAccess[1].grfAccessPermissions = FILE_ALL_ACCESS;
  1345. eaExplicitAccess[1].grfAccessMode = SET_ACCESS;
  1346. eaExplicitAccess[1].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  1347. eaExplicitAccess[1].Trustee.pMultipleTrustee = NULL;
  1348. eaExplicitAccess[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  1349. eaExplicitAccess[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  1350. eaExplicitAccess[1].Trustee.TrusteeType = TRUSTEE_IS_ALIAS;
  1351. eaExplicitAccess[1].Trustee.ptstrName = (LPTSTR) psidBackupOperators;
  1352. //
  1353. // Create a new ACL that contains the new ACEs.
  1354. //
  1355. dwStatus = SetEntriesInAcl(2,
  1356. eaExplicitAccess,
  1357. NULL,
  1358. &paclDiscretionaryAcl
  1359. );
  1360. if (ERROR_SUCCESS != dwStatus) {
  1361. SetLastError(dwStatus);
  1362. bResult = FALSE;
  1363. }
  1364. _AsrpErrExitCode((!bResult), dwStatus, dwStatus);
  1365. //
  1366. // Add the ACL to the security descriptor.
  1367. //
  1368. bResult = SetSecurityDescriptorDacl(
  1369. psaSecurityAttributes->lpSecurityDescriptor,
  1370. TRUE,
  1371. paclDiscretionaryAcl,
  1372. FALSE
  1373. );
  1374. _AsrpErrExitCode((!bResult), dwStatus, GetLastError());
  1375. paclDiscretionaryAcl = NULL; // We shouldn't clean this buffer yet.
  1376. EXIT:
  1377. //
  1378. // Free locally allocated structures
  1379. //
  1380. if (NULL != psidAdministrators) {
  1381. FreeSid(psidAdministrators);
  1382. psidAdministrators = NULL;
  1383. }
  1384. if (NULL != psidBackupOperators) {
  1385. FreeSid(psidBackupOperators);
  1386. psidBackupOperators = NULL;
  1387. }
  1388. if (NULL != paclDiscretionaryAcl) {
  1389. LocalFree(paclDiscretionaryAcl);
  1390. paclDiscretionaryAcl = NULL;
  1391. }
  1392. return bResult;
  1393. } // ConstructSecurityAttributes
  1394. BOOL
  1395. AsrpCleanupSecurityAttributes(
  1396. IN LPSECURITY_ATTRIBUTES psaSecurityAttributes
  1397. )
  1398. {
  1399. BOOL bResult = FALSE;
  1400. BOOL bDaclPresent = FALSE;
  1401. BOOL bDaclDefaulted = TRUE;
  1402. PACL paclDiscretionaryAcl = NULL;
  1403. bResult = GetSecurityDescriptorDacl(
  1404. psaSecurityAttributes->lpSecurityDescriptor,
  1405. &bDaclPresent,
  1406. &paclDiscretionaryAcl,
  1407. &bDaclDefaulted
  1408. );
  1409. if (bResult &&
  1410. bDaclPresent &&
  1411. !bDaclDefaulted &&
  1412. (NULL != paclDiscretionaryAcl)
  1413. ) {
  1414. LocalFree(paclDiscretionaryAcl);
  1415. }
  1416. return TRUE;
  1417. } // CleanupSecurityAttributes
  1418. //
  1419. // This creates an ASR log file at %systemroot%\asr.log,
  1420. // and also initialises Gbl_AsrLogFileHandle.
  1421. //
  1422. VOID
  1423. AsrpInitialiseLogFile()
  1424. {
  1425. PWSTR currentSystemDevice = NULL;
  1426. Gbl_AsrLogFileHandle = NULL;
  1427. Gbl_AsrSystemVolumeHandle = NULL;
  1428. //
  1429. // Get full path to the error file.
  1430. //
  1431. Gbl_AsrLogFilePath = AsrpExpandEnvStrings(Asr_AsrLogFilePath);
  1432. if (!Gbl_AsrLogFilePath) {
  1433. goto OPENSYSTEMHANDLE;
  1434. }
  1435. //
  1436. // Create an empty file (over-write it if it already exists).
  1437. //
  1438. Gbl_AsrLogFileHandle = CreateFileW(
  1439. Gbl_AsrLogFilePath, // lpFileName
  1440. GENERIC_WRITE | GENERIC_READ, // dwDesiredAccess
  1441. FILE_SHARE_READ, // dwShareMode: nobody else should write to the log file while we are
  1442. NULL, // lpSecurityAttributes
  1443. OPEN_ALWAYS, // dwCreationFlags
  1444. FILE_FLAG_WRITE_THROUGH, // dwFlagsAndAttributes: write through so we flush
  1445. NULL // hTemplateFile
  1446. );
  1447. if ((Gbl_AsrLogFileHandle) && (INVALID_HANDLE_VALUE != Gbl_AsrLogFileHandle)) {
  1448. //
  1449. // Move to the end of file
  1450. //
  1451. SetFilePointer(Gbl_AsrLogFileHandle, 0L, NULL, FILE_END);
  1452. }
  1453. else {
  1454. AsrpPrintDbgMsg(_asrlog,
  1455. "Unable to create/open ASR log file at %ws (0x%x)\r\n",
  1456. Gbl_AsrLogFilePath,
  1457. GetLastError()
  1458. );
  1459. }
  1460. OPENSYSTEMHANDLE:
  1461. //
  1462. // Open a handle to the system volume. This is needed since the system
  1463. // disk might otherwise be removed and added back by PnP during the
  1464. // device detecion and re-installation phase (which will cause the
  1465. // HKLM\System\Setup\SystemPartition key to be out-of-sync, and apps/
  1466. // components such as LDM that depend on that key to find the system
  1467. // partition will fail).
  1468. //
  1469. // The more permanent work-around to this involves a change in mountmgr,
  1470. // (such that it updates this key everytime the system volume disappears
  1471. // and reappears) but for now, holding an open handle to the system
  1472. // volume should suffice.
  1473. //
  1474. // See Windows Bugs 155675 for more information.
  1475. //
  1476. currentSystemDevice = AsrpExpandEnvStrings(Asr_SystemDeviceWin32Path);
  1477. if (currentSystemDevice) {
  1478. Gbl_AsrSystemVolumeHandle = CreateFileW(
  1479. currentSystemDevice, // lpFileName
  1480. FILE_READ_ATTRIBUTES, // dwDesiredAccess
  1481. FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode
  1482. NULL, // lpSecurityAttributes
  1483. OPEN_EXISTING, // dwCreationFlags
  1484. FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes: write through so we flush
  1485. NULL // hTemplateFile
  1486. );
  1487. if ((Gbl_AsrSystemVolumeHandle) && (INVALID_HANDLE_VALUE != Gbl_AsrSystemVolumeHandle)) {
  1488. AsrpPrintDbgMsg(_asrinfo, "Opened a handle to the system volume %ws\r\n", currentSystemDevice);
  1489. }
  1490. else {
  1491. AsrpPrintDbgMsg(_asrinfo, "Unable to open a handle to the system volume %ws (0x%x)\r\n",
  1492. currentSystemDevice,
  1493. GetLastError()
  1494. );
  1495. }
  1496. _AsrFree(currentSystemDevice);
  1497. }
  1498. else {
  1499. AsrpPrintDbgMsg(_asrinfo, "Unable to get current system volume (0x%x)\r\n", GetLastError());
  1500. }
  1501. }
  1502. //
  1503. // This creates an empty ASR error file at %systemroot%\asr.err,
  1504. // and also initialises Gbl_AsrErrorFilePath with the full path
  1505. // to asr.err
  1506. //
  1507. VOID
  1508. AsrpInitialiseErrorFile()
  1509. {
  1510. HANDLE errorFileHandle = NULL;
  1511. PWSTR lpOldFileName = NULL;
  1512. DWORD size = 0;
  1513. BOOL bResult = FALSE;
  1514. char UnicodeFlag[3];
  1515. //
  1516. // Get full path to the error file.
  1517. //
  1518. Gbl_AsrErrorFilePath = AsrpExpandEnvStrings(Asr_AsrErrorFilePath);
  1519. if (!Gbl_AsrErrorFilePath) {
  1520. return;
  1521. }
  1522. lpOldFileName = AsrpExpandEnvStrings(Asr_OldAsrErrorFilePath);
  1523. if (lpOldFileName) {
  1524. //
  1525. // If the file already exists, move it to asr.err.old
  1526. //
  1527. MoveFileExW(Gbl_AsrErrorFilePath, lpOldFileName, MOVEFILE_REPLACE_EXISTING);
  1528. }
  1529. //
  1530. // Create an empty file (append to it if it already exists), and close it
  1531. // immediately
  1532. //
  1533. errorFileHandle = CreateFileW(
  1534. Gbl_AsrErrorFilePath, // lpFileName
  1535. GENERIC_WRITE, // dwDesiredAccess
  1536. FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode
  1537. NULL, // lpSecurityAttributes
  1538. CREATE_ALWAYS, // dwCreationFlags
  1539. FILE_FLAG_WRITE_THROUGH, // dwFlagsAndAttributes
  1540. NULL // hTemplateFile
  1541. );
  1542. if ((errorFileHandle) && (INVALID_HANDLE_VALUE != errorFileHandle)) {
  1543. sprintf(UnicodeFlag, "%c%c", 0xFF, 0xFE);
  1544. WriteFile(errorFileHandle, UnicodeFlag, strlen(UnicodeFlag)*sizeof(char), &size, NULL);
  1545. CloseHandle(errorFileHandle);
  1546. DbgPrintEx(DPFLTR_SETUP_ID, DPFLTR_TRACE_LEVEL,
  1547. "ASR %c%lu Create ASR error file at %ws\r\n",
  1548. THIS_MODULE, __LINE__, Gbl_AsrErrorFilePath);
  1549. }
  1550. else {
  1551. DbgPrintEx(DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  1552. "ASR %c%lu (ERROR) Unable to create ASR error file at %ws (0x%lu)\r\n",
  1553. THIS_MODULE, __LINE__, Gbl_AsrErrorFilePath, GetLastError());
  1554. }
  1555. }
  1556. VOID
  1557. AsrpCloseLogFiles() {
  1558. if (Gbl_AsrErrorFilePath) {
  1559. _AsrFree(Gbl_AsrErrorFilePath);
  1560. }
  1561. if (Gbl_AsrLogFilePath) {
  1562. _AsrFree(Gbl_AsrLogFilePath);
  1563. }
  1564. if ((Gbl_AsrLogFileHandle) && (INVALID_HANDLE_VALUE != Gbl_AsrLogFileHandle)) {
  1565. CloseHandle(Gbl_AsrLogFileHandle);
  1566. Gbl_AsrLogFileHandle = NULL;
  1567. }
  1568. }
  1569. //
  1570. // This executes "notepad <Asr-Log-File>". If we encounter a critical
  1571. // failure, we display the error log to the user, and reboot. We
  1572. // document that any critical application that returns a fatal error
  1573. // code is required to make an entry explaining the error in the
  1574. // ASR error file.
  1575. //
  1576. VOID
  1577. AsrpExecuteOnFatalError()
  1578. {
  1579. BOOL result = FALSE;
  1580. DWORD exitCode = 0;
  1581. PWSTR onFatalCmd = NULL;
  1582. if (!Gbl_AsrErrorFilePath) {
  1583. MYASSERT(0 && L"ExecuteOnFatalError called before InitialiseErrorFile: Gbl_ErrorFilePath is NULL");
  1584. return;
  1585. }
  1586. //
  1587. // Make the error file read-only, so that the user's changes
  1588. // aren't accidentally saved.
  1589. //
  1590. result = SetFileAttributesW(Gbl_AsrErrorFilePath, FILE_ATTRIBUTE_READONLY);
  1591. if (!result) {
  1592. AsrpPrintDbgMsg(_asrwarn,
  1593. "Setup was unable to reset file attributes on file [%ws] to read-only (0x%x)\r\n",
  1594. Gbl_AsrErrorFilePath,
  1595. GetLastError()
  1596. );
  1597. }
  1598. //
  1599. // Pop up the ASR failed wizard page.
  1600. //
  1601. //
  1602. // Finally run "notepad <asr-log-file>"
  1603. //
  1604. onFatalCmd = AsrpExpandEnvStrings(Asr_FatalErrorCommand);
  1605. if (!onFatalCmd) {
  1606. //
  1607. // Nothing we can do here--we couldn't find the command
  1608. // to execute on fatal errors. Just bail--this is going
  1609. // to make the system reboot.
  1610. //
  1611. return;
  1612. }
  1613. result = InvokeExternalApplication(
  1614. NULL, // no Application Name
  1615. onFatalCmd, // the full command string
  1616. &exitCode // we want a synchronous execution
  1617. );
  1618. if (!result) {
  1619. SetFileAttributesW(Gbl_AsrErrorFilePath, FILE_ATTRIBUTE_NORMAL);
  1620. AsrpPrintDbgMsg(_asrwarn,
  1621. "Setup was unable to display error file, [%ws] failed (0x%x)\r\n",
  1622. onFatalCmd,
  1623. GetLastError()
  1624. );
  1625. }
  1626. _AsrFree(onFatalCmd);
  1627. }
  1628. BOOL
  1629. AsrpSetFileSecurity(
  1630. )
  1631. {
  1632. DWORD dwStatus = ERROR_SUCCESS;
  1633. SECURITY_ATTRIBUTES securityAttributes;
  1634. SECURITY_DESCRIPTOR securityDescriptor;
  1635. BOOL bResult = FALSE;
  1636. if ((!Gbl_AsrErrorFilePath) || (!Gbl_AsrLogFilePath)) {
  1637. SetLastError(ERROR_FILE_NOT_FOUND);
  1638. AsrpPrintDbgMsg(_asrlog,
  1639. "Unable to set backup operator permissions for log/error files (0x2)\r\n");
  1640. return FALSE;
  1641. }
  1642. securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  1643. securityAttributes.lpSecurityDescriptor = &securityDescriptor;
  1644. securityAttributes.bInheritHandle = FALSE;
  1645. bResult = AsrpConstructSecurityAttributes(&securityAttributes);
  1646. _AsrpErrExitCode((!bResult), dwStatus, GetLastError());
  1647. bResult = SetFileSecurity(Gbl_AsrErrorFilePath,
  1648. DACL_SECURITY_INFORMATION,
  1649. &securityDescriptor
  1650. );
  1651. _AsrpErrExitCode((!bResult), dwStatus, GetLastError());
  1652. AsrpPrintDbgMsg(_asrinfo,
  1653. "Set backup operator permissions for error file at %ws\r\n",
  1654. Gbl_AsrErrorFilePath
  1655. );
  1656. bResult = SetFileSecurity(Gbl_AsrLogFilePath,
  1657. DACL_SECURITY_INFORMATION,
  1658. &securityDescriptor
  1659. );
  1660. _AsrpErrExitCode((!bResult), dwStatus, GetLastError());
  1661. AsrpPrintDbgMsg(_asrinfo,
  1662. "Set backup operator permissions for log file at %ws\r\n",
  1663. Gbl_AsrLogFilePath
  1664. );
  1665. EXIT:
  1666. AsrpCleanupSecurityAttributes(&securityAttributes);
  1667. if (ERROR_SUCCESS != dwStatus) {
  1668. SetLastError(dwStatus);
  1669. }
  1670. if (bResult) {
  1671. AsrpPrintDbgMsg(_asrinfo, "Set backup operator permissions for files\r\n");
  1672. }
  1673. else {
  1674. AsrpPrintDbgMsg(_asrlog,
  1675. "Unable to set backup operator permissions for log/error files (0x%lu)\r\n",
  1676. GetLastError());
  1677. }
  1678. return bResult;
  1679. }
  1680. ///////////////////////////////////////////////////////////////////////////////
  1681. // Public function definitions.
  1682. ///////////////////////////////////////////////////////////////////////////////
  1683. VOID
  1684. AsrInitialize(VOID)
  1685. /*++
  1686. Description:
  1687. Initializes the data structures required to complete ASR (Automated System
  1688. Recovery, aka Disaster Recovery). This consists of reading the asr.sif
  1689. file then initializing a list of recovery applications to be executed.
  1690. Arguments:
  1691. None.
  1692. Returns:
  1693. None.
  1694. --*/
  1695. {
  1696. PWSTR sifName = NULL;
  1697. HINF sifHandle = NULL;
  1698. BOOL result = FALSE;
  1699. UINT errorLine = 0;
  1700. SYSTEMTIME currentTime;
  1701. GetSystemTime(&currentTime);
  1702. //
  1703. // Set the %TEMP% to c:\temp
  1704. //
  1705. AsrpSetEnvironmentVariables();
  1706. //
  1707. // Initialise the log files
  1708. //
  1709. AsrpInitialiseErrorFile();
  1710. AsrpInitialiseLogFile();
  1711. AsrpPrintDbgMsg(_asrlog,
  1712. "Entering GUI-mode Automated System Recovery. UTC: %04hu/%02hu/%02hu %02hu:%02hu:%02hu.%03hu.\r\n",
  1713. currentTime.wYear,
  1714. currentTime.wMonth,
  1715. currentTime.wDay,
  1716. currentTime.wHour,
  1717. currentTime.wMinute,
  1718. currentTime.wSecond,
  1719. currentTime.wMilliseconds
  1720. );
  1721. //
  1722. // Open the asr.sif file
  1723. //
  1724. sifName = AsrpExpandEnvStrings(AsrSifPath);
  1725. if (!sifName) {
  1726. AsrpPrintDbgMsg(_asrerror, "Setup was unable to locate the ASR state file asr.sif.\r\n");
  1727. FatalError(MSG_LOG_SYSINFBAD, L"asr.sif",0,0);
  1728. }
  1729. sifHandle = SetupOpenInfFileW(
  1730. sifName,
  1731. NULL, // Inf Class
  1732. INF_STYLE_WIN4,
  1733. &errorLine // Error-line
  1734. );
  1735. if ((!sifHandle) || (INVALID_HANDLE_VALUE == sifHandle)) {
  1736. AsrpPrintDbgMsg(_asrerror,
  1737. "Setup was unable to open the ASR state file [%ws]. Error-code: 0x%x, Line %lu\r\n",
  1738. sifName,
  1739. GetLastError(),
  1740. errorLine
  1741. );
  1742. _AsrFree(sifName);
  1743. FatalError(MSG_LOG_SYSINFBAD, L"asr.sif",0,0);
  1744. }
  1745. //
  1746. // Add the "last instance" registry entry for ASR.
  1747. //
  1748. AsrpAddRegistryEntry();
  1749. //
  1750. // Set the time-zone information.
  1751. //
  1752. result = AsrpRestoreTimeZoneInformation(sifName);
  1753. if (!result) {
  1754. AsrpPrintDbgMsg(_asrwarn,
  1755. "Setup was unable to restore the time-zone information on the machine. (0x%x) ASR state file %ws\r\n",
  1756. GetLastError(),
  1757. (sifName ? sifName : L"could not be determined")
  1758. );
  1759. }
  1760. else {
  1761. AsrpPrintDbgMsg(_asrlog, "Successfully restored time-zone information.\r\n");
  1762. }
  1763. _AsrFree(sifName);
  1764. //AsrpPerformSifIntegrityCheck(Handle); No check at the moment
  1765. //
  1766. // Make sure the licensed processors key is set. I'm adding this call here
  1767. // since if this key isn't present when we reboot, the system bugchecks with
  1768. // 9A: system_license_violation.
  1769. //
  1770. SetEnabledProcessorCount();
  1771. SetupCloseInfFile(sifHandle);
  1772. Gbl_IsAsrEnabled = TRUE;
  1773. }
  1774. BOOL
  1775. AsrIsEnabled(VOID)
  1776. /*++
  1777. Description:
  1778. Informs the caller whether ASR has been enabled by returning the value of
  1779. the Gbl_IsAsrEnabled flag.
  1780. Arguments:
  1781. None.
  1782. Returns:
  1783. TRUE, if ASR is enabled. Otherwise, FALSE is returned.
  1784. --*/
  1785. {
  1786. return Gbl_IsAsrEnabled;
  1787. }
  1788. VOID
  1789. AsrExecuteRecoveryApps(VOID)
  1790. /*++
  1791. Description:
  1792. Executes the commands in the [COMMANDS] section of the asr.sif file.
  1793. Arguments:
  1794. None.
  1795. Returns:
  1796. None.
  1797. --*/
  1798. {
  1799. BOOL errors = FALSE,
  1800. result = FALSE;
  1801. DWORD exitCode = 0;
  1802. LONG criticalApp = 0;
  1803. PWSTR sifPath = NULL;
  1804. PWSTR application = NULL;
  1805. PASR_RECOVERY_APP_NODE pNode = NULL;
  1806. ASR_RECOVERY_APP_LIST list = {NULL, NULL, 0};
  1807. SYSTEMTIME currentTime;
  1808. PWSTR errString = NULL;
  1809. ASSERT_HEAP_IS_VALID();
  1810. //
  1811. // Restore the non-critical disks.
  1812. //
  1813. SetLastError(ERROR_SUCCESS);
  1814. sifPath = AsrpExpandEnvStrings(AsrSifPath);
  1815. if (sifPath) {
  1816. result = AsrpRestoreNonCriticalDisksW(sifPath, TRUE);
  1817. }
  1818. if (!result) {
  1819. AsrpPrintDbgMsg(_asrwarn,
  1820. "Setup was unable to restore the configuration of some of the disks on the machine. (0x%x) ASR state file %ws\r\n",
  1821. GetLastError(),
  1822. (sifPath ? sifPath : L"could not be determined")
  1823. );
  1824. }
  1825. else {
  1826. AsrpPrintDbgMsg(_asrlog,
  1827. "Successfully recreated disk configurations.\r\n");
  1828. }
  1829. _AsrFree(sifPath);
  1830. ASSERT_HEAP_IS_VALID();
  1831. //
  1832. // Close the system handle
  1833. //
  1834. if ((Gbl_AsrSystemVolumeHandle) && (INVALID_HANDLE_VALUE != Gbl_AsrSystemVolumeHandle)) {
  1835. CloseHandle(Gbl_AsrSystemVolumeHandle);
  1836. Gbl_AsrSystemVolumeHandle = NULL;
  1837. AsrpPrintDbgMsg(_asrinfo, "Closed system device handle.\r\n");
  1838. }
  1839. else {
  1840. AsrpPrintDbgMsg(_asrinfo, "Did not have a valid system device handle to close.\r\n");
  1841. }
  1842. //
  1843. // Set the file security for the log and err files, to allow
  1844. // backup operators to be able to access it on reboot
  1845. //
  1846. AsrpSetFileSecurity();
  1847. AsrpInitExecutionEnv(&list);
  1848. //
  1849. // Sort the list of recovery apps, by sequence number.
  1850. //
  1851. AsrpSortAppListBySequenceNumber(&list);
  1852. //
  1853. // Change the boot timeout value in the boot.ini file. We do this now,
  1854. // since executed apps in the list might result in changing drive letter,
  1855. // which would make finding boot.ini non-trivial.
  1856. //
  1857. if (!ChangeBootTimeout(30)) {
  1858. AsrpPrintDbgMsg(_asrwarn, "Failed to change boot.ini timeout value.\r\n");
  1859. }
  1860. //
  1861. // Remove an application from the list and execute it. Continue until
  1862. // no more applications remain.
  1863. //
  1864. pNode = AsrpRemoveFirstNodeFromList(&list);
  1865. while (pNode && !errors) {
  1866. application = AsrpBuildInvocationString(pNode);
  1867. criticalApp = pNode->CriticalApp;
  1868. //
  1869. // We don't need pNode any more
  1870. //
  1871. if (pNode->RecoveryAppParams) {
  1872. _AsrFree(pNode->RecoveryAppParams);
  1873. }
  1874. _AsrFree(pNode->RecoveryAppCommand);
  1875. _AsrFree(pNode);
  1876. //
  1877. // if the cmd line couldn't be created:
  1878. // for a critical app, fail.
  1879. // for a non-critical app, move on to next
  1880. //
  1881. if (!application) {
  1882. if (0 < criticalApp) {
  1883. errors = TRUE;
  1884. }
  1885. }
  1886. else {
  1887. //
  1888. // Launch the app
  1889. //
  1890. AsrpPrintDbgMsg(_asrlog, "Invoking external recovery application [%ws]\r\n", application);
  1891. exitCode = ERROR_SUCCESS;
  1892. SetLastError(ERROR_SUCCESS);
  1893. result = InvokeExternalApplication(
  1894. NULL, // no Application Name
  1895. application, // the full command string
  1896. &exitCode // we want a synchronous execution
  1897. );
  1898. if (!result) {
  1899. AsrpPrintDbgMsg(_asrerror,
  1900. "Setup was unable to start the recovery application \"%ws\" (0x%x).\r\n",
  1901. application,
  1902. GetLastError()
  1903. );
  1904. //
  1905. // If a critical app couldn't be launched, it's a fatal error
  1906. //
  1907. if (0 < criticalApp) {
  1908. errString = MyLoadString(IDS_ASR_ERROR_UNABLE_TO_LAUNCH_APP);
  1909. if (errString) {
  1910. swprintf(g_szErrorMessage, errString, application, GetLastError());
  1911. AsrpLogErrorMessage(g_szErrorMessage);
  1912. MyFree(errString);
  1913. errString = NULL;
  1914. }
  1915. else {
  1916. FatalError(MSG_LOG_OUTOFMEMORY, L"", 0, 0);
  1917. }
  1918. errors = TRUE;
  1919. }
  1920. }
  1921. else {
  1922. //
  1923. // Application was started: check the return code. If return
  1924. // code is not zero and this is a critical app (ie criticalApp=1)
  1925. // it is a fatal error
  1926. //
  1927. if ((ERROR_SUCCESS != exitCode) && (0 < criticalApp)) {
  1928. AsrpPrintDbgMsg(_asrerror, "The recovery application \"%ws\" returned an error code 0x%x. Since this indicates an unrecoverable error, ASR cannot continue on this machine.\r\n", application, exitCode);
  1929. errString = MyLoadString(IDS_ASR_ERROR_RECOVERY_APP_FAILED);
  1930. if (errString) {
  1931. swprintf(g_szErrorMessage, errString, application, exitCode);
  1932. AsrpLogErrorMessage(g_szErrorMessage);
  1933. MyFree(errString);
  1934. errString = NULL;
  1935. }
  1936. else {
  1937. FatalError(MSG_LOG_OUTOFMEMORY, L"", 0, 0);
  1938. }
  1939. errors = TRUE;
  1940. }
  1941. else {
  1942. AsrpPrintDbgMsg(_asrlog, "The recovery application \"%ws\" returned an exit code of 0x%x\r\n", application, exitCode);
  1943. }
  1944. }
  1945. }
  1946. _AsrFree(application);
  1947. pNode = AsrpRemoveFirstNodeFromList(&list);
  1948. }
  1949. if (errors) {
  1950. //
  1951. // A critical app above did not return 0.
  1952. //
  1953. AsrpExecuteOnFatalError();
  1954. }
  1955. else {
  1956. //
  1957. // We executed all the apps, without any critical failure.
  1958. //
  1959. RemoveRestartability(NULL);
  1960. DeleteLocalSource();
  1961. AsrpMergeSetupLogIfNeeded();
  1962. AsrpPrintDbgMsg(_asrlog, "ASR completed successfully.\r\n");
  1963. }
  1964. GetSystemTime(&currentTime);
  1965. AsrpPrintDbgMsg(_asrlog,
  1966. "Exiting from GUI-mode Automated System Recovery. UTC: %04hu/%02hu/%02hu %02hu:%02hu:%02hu.%03hu.\r\n",
  1967. currentTime.wYear,
  1968. currentTime.wMonth,
  1969. currentTime.wDay,
  1970. currentTime.wHour,
  1971. currentTime.wMinute,
  1972. currentTime.wSecond,
  1973. currentTime.wMilliseconds
  1974. );
  1975. //
  1976. // Clean up global values
  1977. //
  1978. AsrpCloseLogFiles();
  1979. ASSERT_HEAP_IS_VALID();
  1980. }