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.

3546 lines
101 KiB

  1. /******************************************************************************
  2. *
  3. * Copyright (c) 2000 Microsoft Corporation
  4. *
  5. * Module Name:
  6. * snapshot.cpp
  7. *
  8. * Abstract:
  9. * CSnapshot, CSnapshot class functions
  10. *
  11. * Revision History:
  12. * Ashish Sikka (ashishs) 05/05/2000
  13. * created
  14. *
  15. *****************************************************************************/
  16. #include "snapshoth.h"
  17. #include "srrpcapi.h"
  18. #include "srapi.h"
  19. #include "..\datastor\datastormgr.h"
  20. #include "..\service\evthandler.h"
  21. #ifdef THIS_FILE
  22. #undef THIS_FILE
  23. #endif
  24. static char __szTraceSourceFile[] = __FILE__;
  25. #define THIS_FILE __szTraceSourceFile
  26. static LPCWSTR s_cszCOMDBBackupFile = L"ComDb.Dat";
  27. static LPCWSTR s_cszWMIBackupFile = L"Repository";
  28. static LPCWSTR s_cszIISBackupFile = L"IISDB";
  29. static LPCWSTR s_cszIISSuffix = L".MD";
  30. static LPCWSTR s_cszIISBackupPath = L"%windir%\\system32\\inetsrv\\metaback\\";
  31. static LPCWSTR s_cszIISOriginalPath = L"%windir%\\system32\\inetsrv\\metabase.bin";
  32. static LPCWSTR s_cszSnapshotUsrClassLocation = L"Local Settings\\Application Data\\Microsoft\\Windows\\UsrClass.dat";
  33. static LPCWSTR s_cszSnapshotUsrClass = L"USRCLASS_";
  34. static LPCWSTR s_cszSnapshotNtUser = L"NTUSER_";
  35. static LPCWSTR s_cszClassesKey = L"_Classes";
  36. static LPCWSTR s_cszSnapshotUsersDefaultKey = L".DEFAULT";
  37. static LPCWSTR s_cszSnapshotHiveList = L"System\\CurrentControlSet\\Control\\Hivelist";
  38. static LPCWSTR s_cszRestoreTempKey = L"Restore122312";
  39. static LPCWSTR s_cszHKLMPrefix = L"\\Registry\\Machine\\";
  40. static LPCSTR s_cszRegDBBackupFn = "RegDBBackup";
  41. static LPCSTR s_cszRegDBRestoreFn = "RegDBRestore";
  42. #define VALIDATE_DWRET(str) \
  43. if ( dwRet != ERROR_SUCCESS ) \
  44. { \
  45. ErrorTrace(0, str " failed ec=%d", dwRet); \
  46. goto Exit; \
  47. } \
  48. #define LOAD_KEY_NAME TEXT("BackupExecReg")
  49. DWORD SnapshotCopyFile(WCHAR * pszSrc,
  50. WCHAR * pszDest);
  51. struct WMISnapshotParam
  52. {
  53. HANDLE hEvent;
  54. CRestorePoint *pRpLast;
  55. BOOL fSerialized;
  56. WCHAR szSnapshotDir[MAX_PATH];
  57. };
  58. DWORD WINAPI DoWMISnapshot(VOID * pParam);
  59. DWORD DoIISSnapshot(WCHAR * pszSnapshotDir);
  60. DWORD SnapshotRestoreFilelistFiles(WCHAR * pszSnapshotDir, BOOL fSnapshot);
  61. DWORD CallSnapshotCallbacks(LPCWSTR pszEnumKey, LPCWSTR pszSnapshotDir, BOOL fSnapshot);
  62. CSnapshot::CSnapshot()
  63. {
  64. TraceFunctEnter("CSnapshot::CSnapshot");
  65. m_hRegdbDll = NULL;
  66. m_pfnRegDbBackup = NULL;
  67. m_pfnRegDbRestore = NULL;
  68. TraceFunctLeave();
  69. }
  70. CSnapshot::~CSnapshot()
  71. {
  72. TraceFunctEnter("CSnapshot::~CSnapshot");
  73. m_pfnRegDbBackup = NULL;
  74. m_pfnRegDbRestore = NULL;
  75. if (NULL != m_hRegdbDll)
  76. {
  77. _VERIFY(TRUE==FreeLibrary(m_hRegdbDll));
  78. }
  79. TraceFunctLeave();
  80. }
  81. DWORD
  82. CSnapshot::DeleteSnapshot(WCHAR * pszRestoreDir)
  83. {
  84. TraceFunctEnter("CSnapshot::DeleteSnapshot");
  85. WCHAR szSnapshotDir[MAX_PATH];
  86. BOOL fStop=FALSE;
  87. DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
  88. // create the snapshot directory name from the restore directory
  89. // name and create the actual directory.
  90. lstrcpy(szSnapshotDir, pszRestoreDir);
  91. lstrcat(szSnapshotDir, SNAPSHOT_DIR_NAME);
  92. dwErr = Delnode_Recurse(szSnapshotDir,
  93. TRUE, // Delete the ROOT dir
  94. &fStop);
  95. if (dwErr != ERROR_SUCCESS)
  96. {
  97. ErrorTrace(0, "Fatal error %ld deleting snapshot directory",dwErr);
  98. dwReturn = dwErr;
  99. goto cleanup;
  100. }
  101. dwReturn = ERROR_SUCCESS;
  102. cleanup:
  103. TraceFunctLeave();
  104. return dwReturn;
  105. }
  106. // the following function checks to see if the file passed in is a
  107. // temporary copy of a reghive created before the restore.
  108. // It does this by checking if the file suffix is s_cszRegHiveCopySuffix
  109. BOOL IsRestoreCopy(const WCHAR * pszFileName)
  110. {
  111. BOOL fReturn=FALSE;
  112. DWORD dwLength, dwSuffixLen;
  113. // Find
  114. dwLength = lstrlen(pszFileName);
  115. dwSuffixLen = lstrlen(s_cszRegHiveCopySuffix);
  116. if (dwSuffixLen > dwLength)
  117. {
  118. goto cleanup;
  119. }
  120. dwLength -= dwSuffixLen;
  121. // If the file is indeed a restore copy, dwLength points to the
  122. // first character of s_cszRegHiveCopySuffix
  123. if (0==lstrcmpi(pszFileName+dwLength, s_cszRegHiveCopySuffix))
  124. {
  125. fReturn = TRUE;
  126. }
  127. cleanup:
  128. return fReturn;
  129. }
  130. DWORD
  131. ProcessPendingRenames(LPWSTR pszSnapshotDir)
  132. {
  133. TraceFunctEnter("ProcessPendingRenames");
  134. WCHAR szDest[MAX_PATH];
  135. DWORD dwRc;
  136. HKEY hKey = NULL;
  137. dwRc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  138. s_cszSessionManagerRegKey,
  139. 0,
  140. KEY_READ,
  141. &hKey);
  142. if (ERROR_SUCCESS == dwRc)
  143. {
  144. DWORD dwType = REG_MULTI_SZ;
  145. DWORD dwSize = 0;
  146. dwRc = RegQueryValueEx(hKey, s_cszMoveFileExRegValue, 0, &dwType, NULL, &dwSize);
  147. if (dwRc == ERROR_SUCCESS && dwSize > 0)
  148. {
  149. WCHAR * pwcBuffer = new WCHAR [dwSize / 2];
  150. if (pwcBuffer == NULL)
  151. {
  152. trace(0, "Error allocating pwcBuffer");
  153. dwRc = ERROR_NOT_ENOUGH_MEMORY;
  154. goto done;
  155. }
  156. dwRc = RegQueryValueEx(hKey, s_cszMoveFileExRegValue,
  157. NULL, &dwType, (BYTE *) pwcBuffer, &dwSize);
  158. if (ERROR_SUCCESS == dwRc && REG_MULTI_SZ == dwType)
  159. {
  160. int iFirst = 0;
  161. int iSecond = 0;
  162. int iFile = 1;
  163. while ((iFirst < (int) dwSize/2) && pwcBuffer[iFirst] != L'\0')
  164. {
  165. iSecond = iFirst + lstrlenW(&pwcBuffer[iFirst]) + 1;
  166. DebugTrace(0, "Src : %S, Dest : %S", &pwcBuffer[iFirst], &pwcBuffer[iSecond]);
  167. if (pwcBuffer[iSecond] != L'\0')
  168. {
  169. // snapshot the source file to a file MFEX-i.DAT in the snapshot dir
  170. wsprintf(szDest, L"%s\\MFEX-%d.DAT", pszSnapshotDir, iFile++);
  171. SRCopyFile(&pwcBuffer[iFirst+4], szDest);
  172. }
  173. iFirst = iSecond + lstrlenW(&pwcBuffer[iSecond]) + 1;
  174. }
  175. }
  176. delete [] pwcBuffer;
  177. }
  178. else
  179. {
  180. dwRc = ERROR_SUCCESS;
  181. }
  182. }
  183. else
  184. {
  185. trace(0, "! RegOpenKeyEx on %S : %ld", s_cszSessionManagerRegKey, dwRc);
  186. }
  187. done:
  188. if (hKey)
  189. RegCloseKey(hKey);
  190. TraceFunctLeave();
  191. return dwRc;
  192. }
  193. DWORD
  194. CSnapshot::CreateSnapshot(WCHAR * pszRestoreDir, HMODULE hCOMDll, LPWSTR pszRpLast, BOOL fSerialized)
  195. {
  196. TraceFunctEnter("CSnapshot::CreateSnapshot");
  197. HANDLE hThread = NULL;
  198. HANDLE hEvent = NULL;
  199. WMISnapshotParam * pwsp = NULL;
  200. WCHAR pszSnapShotDir[MAX_PATH];
  201. DWORD dwErr, dwAttrs;
  202. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  203. BOOL fCoInitialized = FALSE;
  204. BOOL fWMISnapshotParamCleanup = TRUE;
  205. HRESULT hr;
  206. CTokenPrivilege tp;
  207. // create the snapshot directory name from the restore directory
  208. // name and create the actual directory.
  209. lstrcpy(pszSnapShotDir, pszRestoreDir);
  210. lstrcat(pszSnapShotDir, SNAPSHOT_DIR_NAME);
  211. if (FALSE == CreateDirectory( pszSnapShotDir, // directory name
  212. NULL)) // SD
  213. {
  214. dwErr = GetLastError();
  215. if (ERROR_ALREADY_EXISTS != dwErr)
  216. {
  217. ErrorTrace(0, "Fatal error %ld creating snapshot directory",dwErr);
  218. goto cleanup;
  219. }
  220. }
  221. // set the directory to be uncompressed by default
  222. dwAttrs = GetFileAttributesW (pszSnapShotDir);
  223. if ( (dwAttrs != INVALID_FILE_SIZE) &&
  224. (0 != (FILE_ATTRIBUTE_COMPRESSED & dwAttrs)) )
  225. {
  226. dwErr = CompressFile ( pszSnapShotDir,
  227. FALSE, // uncompress
  228. TRUE ); // target is a directory
  229. if (dwErr != ERROR_SUCCESS)
  230. {
  231. ErrorTrace(0, "! CreateDataStore CompressFile : %ld", dwErr);
  232. // this is not a fatal error
  233. }
  234. }
  235. pwsp = new WMISnapshotParam;
  236. if (NULL == pwsp)
  237. {
  238. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  239. ErrorTrace(0, "cannot allocate CWMISnapshotParam");
  240. goto cleanup;
  241. }
  242. if (pszRpLast)
  243. {
  244. pwsp->pRpLast = new CRestorePoint;
  245. if (NULL == pwsp->pRpLast)
  246. {
  247. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  248. ErrorTrace(0, "cannot allocate CRestorePoint");
  249. goto cleanup;
  250. }
  251. pwsp->pRpLast->SetDir(pszRpLast);
  252. }
  253. else
  254. {
  255. pwsp->pRpLast = NULL;
  256. }
  257. lstrcpyW (pwsp->szSnapshotDir, pszSnapShotDir);
  258. pwsp->fSerialized = fSerialized;
  259. hEvent = CreateEvent (NULL, TRUE, FALSE, NULL); // manual reset
  260. if (NULL == hEvent )
  261. {
  262. dwReturn = GetLastError();
  263. ErrorTrace(0, "! CreateEvent : %ld", dwReturn);
  264. goto cleanup;
  265. }
  266. if (FALSE == DuplicateHandle (GetCurrentProcess(),
  267. hEvent,
  268. GetCurrentProcess(),
  269. &pwsp->hEvent,
  270. 0, FALSE, DUPLICATE_SAME_ACCESS))
  271. {
  272. dwReturn = GetLastError();
  273. ErrorTrace(0, "! DuplicateHandle : %ld", dwReturn);
  274. goto cleanup;
  275. }
  276. if (! fSerialized)
  277. {
  278. trace(0, "Parallellizing WMI snapshot");
  279. hThread = CreateThread (NULL, 0, DoWMISnapshot, pwsp, 0, NULL);
  280. if (hThread == NULL)
  281. {
  282. dwReturn = GetLastError();
  283. ErrorTrace(0, "! CreateThread : %ld", dwReturn);
  284. CloseHandle (pwsp->hEvent);
  285. pwsp->hEvent = NULL;
  286. goto cleanup;
  287. }
  288. if (g_pEventHandler)
  289. g_pEventHandler->GetCounter()->Up();
  290. fWMISnapshotParamCleanup = FALSE; // ownership transferred
  291. }
  292. // before doing the registry snapshot, clear the restore error
  293. // this will prevent us from snapshotting a registry that has
  294. // this error set. Note this that error is only used for the
  295. // restore process and we do not want to restore any regsitries
  296. // what have this error set.
  297. _VERIFY(TRUE==SetRestoreError(ERROR_SUCCESS)); // clear this error
  298. dwErr = ProcessPendingRenames(pszSnapShotDir);
  299. if (dwErr != ERROR_SUCCESS)
  300. {
  301. dwReturn = dwErr;
  302. goto cleanup;
  303. }
  304. dwErr = tp.SetPrivilegeInAccessToken(SE_BACKUP_NAME);
  305. if (ERROR_SUCCESS != dwErr)
  306. {
  307. ErrorTrace(0, "SetPrivilegeInAccessToken failed ec=%d", dwErr);
  308. dwReturn = ERROR_PRIVILEGE_NOT_HELD;
  309. goto cleanup;
  310. }
  311. // Create resgistry snapshot
  312. dwErr = DoRegistrySnapshot(pszSnapShotDir);
  313. if (dwErr != ERROR_SUCCESS)
  314. {
  315. dwReturn = dwErr;
  316. goto cleanup;
  317. }
  318. //snapshot files listed in filelist.xml
  319. dwErr = SnapshotRestoreFilelistFiles(pszSnapShotDir, TRUE);
  320. if (dwErr != ERROR_SUCCESS)
  321. {
  322. dwReturn = dwErr;
  323. goto cleanup;
  324. }
  325. // do COM snapshot
  326. dwErr = DoCOMDbSnapshot(pszSnapShotDir, hCOMDll);
  327. if (dwErr != ERROR_SUCCESS)
  328. {
  329. dwReturn = dwErr;
  330. goto cleanup;
  331. }
  332. hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
  333. if (hr == RPC_E_CHANGED_MODE)
  334. {
  335. //
  336. // someone called it with other mode
  337. //
  338. hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );
  339. }
  340. if (FAILED(hr))
  341. {
  342. dwReturn = (DWORD) hr;
  343. ErrorTrace(0, "! CoInitializeEx : %ld", dwReturn);
  344. goto cleanup;
  345. }
  346. fCoInitialized = TRUE;
  347. // do IIS snapshot
  348. dwErr = DoIISSnapshot(pszSnapShotDir);
  349. if (dwErr != ERROR_SUCCESS)
  350. {
  351. dwReturn = dwErr;
  352. goto cleanup;
  353. }
  354. lstrcatW (pszSnapShotDir, L"\\domain.txt");
  355. dwErr = GetDomainMembershipInfo (pszSnapShotDir, NULL);
  356. if (dwErr != ERROR_SUCCESS)
  357. {
  358. dwReturn = dwErr;
  359. trace(0, "! GetDomainMembershipInfo : %ld", dwErr);
  360. goto cleanup;
  361. }
  362. // if serialized WMI snapshot, do it here
  363. if (fSerialized)
  364. {
  365. trace(0, "Serializing WMI snapshot");
  366. fWMISnapshotParamCleanup = FALSE;
  367. dwReturn = DoWMISnapshot(pwsp);
  368. if (dwReturn != ERROR_SUCCESS)
  369. {
  370. trace(0, "! DoWMISnapshot : %ld", dwErr);
  371. goto cleanup;
  372. }
  373. }
  374. else
  375. {
  376. // wait for the WMI Pause to finish
  377. dwErr = WaitForSingleObject (hEvent, CLock::TIMEOUT);
  378. if (WAIT_TIMEOUT == dwErr)
  379. {
  380. trace (0, "WMI thread timed out");
  381. }
  382. else if (WAIT_FAILED == dwErr)
  383. {
  384. trace (0, "WaitForSingleObject failed");
  385. }
  386. trace(0, "WMI Pause is done");
  387. }
  388. dwReturn = ERROR_SUCCESS;
  389. cleanup:
  390. if (hEvent != NULL)
  391. {
  392. CloseHandle (hEvent);
  393. }
  394. if (fWMISnapshotParamCleanup && NULL != pwsp)
  395. {
  396. if (pwsp->pRpLast)
  397. delete pwsp->pRpLast;
  398. delete pwsp;
  399. trace(0, "CreateSnapshot released pwsp");
  400. }
  401. if (fCoInitialized)
  402. CoUninitialize();
  403. if (hThread != NULL)
  404. CloseHandle (hThread);
  405. TraceFunctLeave();
  406. return dwReturn;
  407. }
  408. BOOL IsWellKnownHKLMHive(WCHAR * pszHiveName)
  409. {
  410. return ( (0==lstrcmpi(pszHiveName, s_cszSoftwareHiveName)) ||
  411. (0==lstrcmpi(pszHiveName, s_cszSystemHiveName )) ||
  412. (0==lstrcmpi(pszHiveName, s_cszSamHiveName )) ||
  413. (0==lstrcmpi(pszHiveName, s_cszSecurityHiveName)) );
  414. }
  415. DWORD SaveRegKey(HKEY hKey, // handle to parent key
  416. const WCHAR * pszSubKeyName, // name of subkey to backup
  417. WCHAR * pszFileName) // filename of backup file
  418. {
  419. TraceFunctEnter("SaveRegKey");
  420. DWORD dwErr, dwReturn = ERROR_INTERNAL_ERROR;
  421. DWORD dwDisposition;
  422. HKEY hKeyToBackup = NULL;
  423. // open the key - pass the REG_OPTION_BACKUP_RESTORE to bypass
  424. // security checking
  425. dwErr = RegCreateKeyEx(hKey, // handle to open key
  426. pszSubKeyName, // subkey name
  427. 0, // reserved
  428. NULL, // class string
  429. REG_OPTION_BACKUP_RESTORE, // special options
  430. KEY_READ, // desired security access
  431. NULL, // inheritance
  432. &hKeyToBackup, // key handle
  433. &dwDisposition); // disposition value buffer
  434. if (ERROR_SUCCESS != dwErr)
  435. {
  436. ErrorTrace(0, "RegCreateKeyEx failed for %S, error %ld",
  437. pszSubKeyName, dwErr);
  438. dwReturn = dwErr;
  439. goto cleanup;
  440. }
  441. // now make sure that the key already existed - else delete the key
  442. if (REG_OPENED_EXISTING_KEY != dwDisposition)
  443. {
  444. // no key existed - delete the key
  445. ErrorTrace(0, "Key %S did not exist, error %ld",
  446. pszSubKeyName, dwErr);
  447. dwReturn = ERROR_FILE_NOT_FOUND;
  448. _VERIFY(ERROR_SUCCESS==RegCloseKey(hKeyToBackup));
  449. hKeyToBackup = NULL;
  450. _VERIFY(ERROR_SUCCESS==RegDeleteKey(hKey, // handle to open key
  451. pszSubKeyName));// subkey name
  452. // BUGBUG test above case
  453. goto cleanup;
  454. }
  455. dwErr = RegSaveKeyEx(hKeyToBackup,// handle to key
  456. pszFileName,// data file
  457. NULL,// SD
  458. REG_NO_COMPRESSION);
  459. if (ERROR_SUCCESS != dwErr)
  460. {
  461. ErrorTrace(0, "RegSaveKey failed for %S, error %ld",
  462. pszSubKeyName, dwErr);
  463. LogDSFileTrace(0,L"File was ", pszFileName);
  464. dwReturn = dwErr;
  465. goto cleanup;
  466. }
  467. dwReturn = ERROR_SUCCESS;
  468. cleanup:
  469. if (NULL != hKeyToBackup)
  470. {
  471. _VERIFY(ERROR_SUCCESS==RegCloseKey(hKeyToBackup));
  472. }
  473. TraceFunctLeave();
  474. return dwReturn;
  475. }
  476. // the saved NTUser.dat file name is of the form
  477. // _REGISTRY_USER_NTUSER_S-1-9-9-09
  478. DWORD CreateNTUserDatPath(WCHAR * pszDest,
  479. DWORD dwDestLength, // length in characters
  480. WCHAR * pszSnapshotDir,
  481. WCHAR * pszUserSID)
  482. {
  483. TraceFunctEnter("CreateNTUserDatPath");
  484. DWORD dwLengthRequired;
  485. dwLengthRequired = lstrlen(pszSnapshotDir) + lstrlen(s_cszUserPrefix) +
  486. lstrlen(s_cszSnapshotNtUser)+ lstrlen(pszUserSID) +2;
  487. if (dwDestLength < dwLengthRequired)
  488. {
  489. ErrorTrace(0, "Insuffcient buffer. Buffer passed in %d, Required %d",
  490. dwDestLength, dwLengthRequired);
  491. TraceFunctLeave();
  492. return ERROR_INSUFFICIENT_BUFFER;
  493. }
  494. wsprintf(pszDest, L"%s\\%s%s%s", pszSnapshotDir, s_cszUserPrefix,
  495. s_cszSnapshotNtUser, pszUserSID);
  496. TraceFunctLeave();
  497. return ERROR_SUCCESS;
  498. }
  499. // the saved UsrClass.dat file name is of the form
  500. // _REGISTRY_USER_USRCLASS_S-1-9-9-09
  501. DWORD CreateUsrClassPath(WCHAR * pszDest,
  502. DWORD dwDestLength, // length in characters
  503. WCHAR * pszSnapshotDir,
  504. WCHAR * pszUserSID)
  505. {
  506. TraceFunctEnter("CreateUsrClassPath");
  507. DWORD dwLengthRequired;
  508. dwLengthRequired = lstrlen(pszSnapshotDir) + lstrlen(s_cszUserPrefix) +
  509. lstrlen(s_cszSnapshotUsrClass)+ lstrlen(pszUserSID) +2;
  510. if (dwDestLength < dwLengthRequired)
  511. {
  512. ErrorTrace(0, "Insuffcient buffer. Buffer passed in %d, Required %d",
  513. dwDestLength, dwLengthRequired);
  514. TraceFunctLeave();
  515. return ERROR_INSUFFICIENT_BUFFER;
  516. }
  517. wsprintf(pszDest, L"%s\\%s%s%s", pszSnapshotDir, s_cszUserPrefix,
  518. s_cszSnapshotUsrClass, pszUserSID);
  519. TraceFunctLeave();
  520. return ERROR_SUCCESS;
  521. }
  522. //
  523. // function to write movefileex entries to a saved system hive file
  524. //
  525. DWORD
  526. SrMoveFileEx(
  527. LPWSTR pszSnapshotDir,
  528. LPWSTR pszSrc,
  529. LPWSTR pszDest)
  530. {
  531. TraceFunctEnter("SrMoveFileEx");
  532. DWORD dwErr = ERROR_SUCCESS;
  533. HKEY hkMount = NULL;
  534. DWORD cbData1 = 0;
  535. PBYTE pNewMFE = NULL, pOldMFE = NULL, pNewPos = NULL;
  536. BOOL fRegLoaded = FALSE;
  537. WCHAR szNewEntry1[MAX_PATH];
  538. WCHAR szNewEntry2[MAX_PATH];
  539. WCHAR szNewEntry3[MAX_PATH];
  540. DWORD cbNewEntry1 = 0, cbNewEntry2 = 0, cbNewEntry3 = 0;
  541. WCHAR szSysHive[MAX_PATH];
  542. //
  543. // load system hive file
  544. //
  545. wsprintf(szSysHive, L"%s\\%s%s%s", pszSnapshotDir,
  546. s_cszHKLMFilePrefix, s_cszSystemHiveName, s_cszRegHiveCopySuffix);
  547. CHECKERR(RegLoadKey( HKEY_LOCAL_MACHINE, s_cszRegHiveTmp, szSysHive ),
  548. L"RegLoadKey");
  549. fRegLoaded = TRUE;
  550. CHECKERR(RegOpenKey( HKEY_LOCAL_MACHINE, s_cszRegHiveTmp, &hkMount ),
  551. L"RegOpenKey");
  552. //
  553. // get old entries
  554. //
  555. lstrcpy(szSysHive, s_cszRegLMSYSSessionMan);
  556. ChangeCCS(hkMount, szSysHive);
  557. pOldMFE = (PBYTE) SRGetRegMultiSz( hkMount, szSysHive, SRREG_VAL_MOVEFILEEX, &cbData1 );
  558. //
  559. // alloc mem for old + new
  560. // allocate enough to hold 3 new paths + some extra characters
  561. //
  562. pNewMFE = (PBYTE) malloc(cbData1 + 4*MAX_PATH*sizeof(WCHAR));
  563. if (! pNewMFE)
  564. {
  565. ErrorTrace(0, "Out of memory");
  566. dwErr = ERROR_OUTOFMEMORY;
  567. goto Err;
  568. }
  569. if (pOldMFE)
  570. memcpy(pNewMFE, pOldMFE, cbData1);
  571. //
  572. // format new entries - a delete and a rename
  573. //
  574. wsprintf(szNewEntry2, L"\\\?\?\\%s", pszSrc);
  575. cbNewEntry2 = (lstrlen(szNewEntry2) + 1)*sizeof(WCHAR);
  576. wsprintf(szNewEntry3, L"!\\\?\?\\%s", pszDest);
  577. cbNewEntry3 = (lstrlen(szNewEntry3) + 1)*sizeof(WCHAR);
  578. DebugTrace(0, "%S", szNewEntry2);
  579. DebugTrace(0, "%S", szNewEntry3);
  580. //
  581. // find position to insert new entries - overwrite trailing '\0'
  582. //
  583. if (pOldMFE)
  584. {
  585. DebugTrace(0, "Old MFE entries exist");
  586. cbData1 -= sizeof(WCHAR);
  587. pNewPos = pNewMFE + cbData1;
  588. }
  589. else
  590. {
  591. DebugTrace(0, "No old MFE entries exist");
  592. pNewPos = pNewMFE;
  593. }
  594. //
  595. // append rename
  596. //
  597. memcpy(pNewPos, (BYTE *) szNewEntry2, cbNewEntry2);
  598. pNewPos += cbNewEntry2;
  599. memcpy(pNewPos, (BYTE *) szNewEntry3, cbNewEntry3);
  600. pNewPos += cbNewEntry3;
  601. //
  602. // add trailing '\0'
  603. //
  604. *((LPWSTR) pNewPos) = L'\0';
  605. //
  606. // write back to registry
  607. //
  608. if (! SRSetRegMultiSz( hkMount,
  609. szSysHive,
  610. SRREG_VAL_MOVEFILEEX,
  611. (LPWSTR) pNewMFE,
  612. cbData1 + cbNewEntry2 + cbNewEntry3 + sizeof(WCHAR)))
  613. {
  614. ErrorTrace(0, "! SRSetRegMultiSz");
  615. dwErr = ERROR_INTERNAL_ERROR;
  616. }
  617. Err:
  618. if (hkMount != NULL)
  619. RegCloseKey(hkMount);
  620. if (fRegLoaded)
  621. RegUnLoadKey(HKEY_LOCAL_MACHINE, s_cszRegHiveTmp);
  622. if (pOldMFE)
  623. delete pOldMFE;
  624. if (pNewMFE)
  625. free(pNewMFE);
  626. TraceFunctLeave();
  627. return dwErr;
  628. }
  629. // the saved UsrClass.dat file name is of the form
  630. // _REGISTRY_USER_USRCLASS_S-1-9-9-09
  631. DWORD CreateUsrDefaultPath(WCHAR * pszDest,
  632. DWORD dwDestLength, // length in characters
  633. WCHAR * pszSnapshotDir)
  634. {
  635. TraceFunctEnter("CreateUsrDefaultPath");
  636. DWORD dwLengthRequired;
  637. dwLengthRequired = lstrlen(pszSnapshotDir) + lstrlen(s_cszUserPrefix) +
  638. lstrlen(s_cszSnapshotUsersDefaultKey) +2;
  639. if (dwDestLength < dwLengthRequired)
  640. {
  641. ErrorTrace(0, "Insuffcient buffer. Buffer passed in %d, Required %d",
  642. dwDestLength, dwLengthRequired);
  643. TraceFunctLeave();
  644. return ERROR_INSUFFICIENT_BUFFER;
  645. }
  646. wsprintf(pszDest, L"%s\\%s%s", pszSnapshotDir, s_cszUserPrefix,
  647. s_cszSnapshotUsersDefaultKey);
  648. TraceFunctLeave();
  649. return ERROR_SUCCESS;
  650. }
  651. DWORD SetNewRegistry(HKEY hBigKey, // handle to open key
  652. const WCHAR * pszHiveName, // subkey name
  653. WCHAR * pszDataFile, // data file
  654. WCHAR * pszOriginalFile,
  655. WCHAR * pszSnapshotDir)
  656. {
  657. TraceFunctEnter("SetNewRegistry");
  658. DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR, dwDisposition;
  659. WCHAR szBackupFile[MAX_PATH]; // backup file
  660. HKEY hLocalKey=NULL;
  661. REGSAM samDesired = MAXIMUM_ALLOWED;
  662. WCHAR szTempRegCopy[MAX_PATH];
  663. // first check to see if the file is a copy created for this
  664. // restore process. If not, we need to create a copy since
  665. // RegReplaceKey removes the input file.
  666. if (FALSE == IsRestoreCopy(pszDataFile))
  667. {
  668. wsprintf(szTempRegCopy, L"%s%s", pszDataFile,
  669. s_cszRegHiveCopySuffix);
  670. dwErr = SnapshotCopyFile(pszDataFile, szTempRegCopy);
  671. if (ERROR_SUCCESS != dwErr)
  672. {
  673. dwReturn = dwErr;
  674. goto cleanup;
  675. }
  676. }
  677. else
  678. {
  679. lstrcpy(szTempRegCopy, pszDataFile);
  680. }
  681. wsprintf(szBackupFile, L"%s%s",szTempRegCopy,s_cszRegReplaceBackupSuffix);
  682. dwErr = RegCreateKeyEx( hBigKey,// handle to open key
  683. pszHiveName,// subkey name
  684. 0,// reserved
  685. NULL,// class string
  686. REG_OPTION_BACKUP_RESTORE,// special options
  687. samDesired,// desired security access
  688. NULL,// inheritance
  689. &hLocalKey,// key handle
  690. &dwDisposition );// disposition value buffer
  691. if ( ERROR_SUCCESS != dwErr )
  692. {
  693. ErrorTrace(0, "RegCreateKeyEx failed for %S, error %ld",
  694. pszHiveName, dwErr);
  695. dwReturn = dwErr;
  696. goto cleanup;
  697. }
  698. dwErr = RegReplaceKey( hLocalKey,
  699. NULL,
  700. szTempRegCopy,
  701. szBackupFile );
  702. if ( dwErr != ERROR_SUCCESS )
  703. {
  704. ErrorTrace(0, "RegReplaceKey failed for %S, error %ld",
  705. pszHiveName, dwErr);
  706. LogDSFileTrace(0,L"File was ", szTempRegCopy);
  707. //
  708. // last ditch effort - try movefileex
  709. //
  710. if (pszSnapshotDir)
  711. {
  712. DebugTrace(0, "Trying movefileex");
  713. dwReturn = SrMoveFileEx(pszSnapshotDir, szTempRegCopy, pszOriginalFile);
  714. if (dwReturn != ERROR_SUCCESS)
  715. {
  716. ErrorTrace(0, "! SrMoveFileEx : %ld", dwReturn);
  717. goto cleanup;
  718. }
  719. }
  720. else
  721. {
  722. _ASSERT(0);
  723. // we can't do anything here
  724. }
  725. }
  726. dwReturn = ERROR_SUCCESS;
  727. cleanup:
  728. if (NULL != hLocalKey)
  729. {
  730. dwErr = RegCloseKey( hLocalKey );
  731. _ASSERT(ERROR_SUCCESS==dwErr);
  732. }
  733. TraceFunctLeave();
  734. return dwReturn;
  735. }
  736. // this function copies the file - it takes care of the attributes
  737. // (like read only and hidden) which prevent overwrite of the file.
  738. DWORD SnapshotCopyFile(WCHAR * pszSrc,
  739. WCHAR * pszDest)
  740. {
  741. TraceFunctEnter("SnapshotCopyFile");
  742. DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR, dwAttr;
  743. BOOL fRestoreAttr = FALSE;
  744. // if destination file does not exist, ignore
  745. if (DoesFileExist(pszDest))
  746. {
  747. dwAttr =GetFileAttributes(pszDest); // name of file or directory
  748. if (dwAttr == -1)
  749. {
  750. // keep going. Maybe the copy will succeed
  751. dwErr = GetLastError();
  752. ErrorTrace(0, "GetFileAttributes failed %d", dwErr);
  753. LogDSFileTrace(0,L"File was ", pszDest);
  754. }
  755. else
  756. {
  757. // we need to keep track of which attributes we will restore.
  758. dwAttr = dwAttr & (FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|
  759. FILE_ATTRIBUTE_NORMAL|
  760. FILE_ATTRIBUTE_NOT_CONTENT_INDEXED|
  761. FILE_ATTRIBUTE_OFFLINE|FILE_ATTRIBUTE_READONLY|
  762. FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_TEMPORARY);
  763. fRestoreAttr = TRUE;
  764. // now set the attributes of the destination file to be
  765. // normal so that we can overwrite this file
  766. if (!SetFileAttributes( pszDest, // file name
  767. FILE_ATTRIBUTE_NORMAL )) // attributes
  768. {
  769. // keep going. Maybe the copy will succeed
  770. dwErr = GetLastError();
  771. ErrorTrace(0, "SetFileAttributes failed %d", dwErr);
  772. LogDSFileTrace(0,L"File was ", pszDest);
  773. }
  774. }
  775. }
  776. dwErr = SRCopyFile(pszSrc, pszDest);
  777. if (dwErr != ERROR_SUCCESS)
  778. {
  779. ErrorTrace(0, "SRCopyFile failed. ec=%d", dwErr);
  780. LogDSFileTrace(0,L"src= ", pszSrc);
  781. LogDSFileTrace(0,L"dst= ", pszDest);
  782. dwReturn = dwErr;
  783. goto cleanup;
  784. }
  785. dwReturn = ERROR_SUCCESS;
  786. cleanup:
  787. if (TRUE == fRestoreAttr)
  788. {
  789. // now restore the attributes of the destination file
  790. if (!SetFileAttributes( pszDest, // file name
  791. dwAttr )) // attributes
  792. {
  793. dwErr = GetLastError();
  794. ErrorTrace(0, "SetFileAttributes failed %d", dwErr);
  795. LogDSFileTrace(0,L"File was ", pszDest);
  796. }
  797. }
  798. TraceFunctLeave();
  799. return dwReturn;
  800. }
  801. // the following function attempts to copy the user profile hives
  802. // (ntuser.dat and usrclass.dat) from the profile path (or vice versa).
  803. // This can fail if the user's profile is in use.
  804. //
  805. // if fRestore is TRUE it restores the profile
  806. // if fRestore is FALSE it snapshots the profile
  807. DWORD CopyUserProfile(HKEY hKeyProfileList,
  808. WCHAR * pszUserSID,
  809. WCHAR * pszSnapshotDir,
  810. BOOL fRestore,
  811. WCHAR * pszNTUserPath)
  812. {
  813. TraceFunctEnter("CopyUserProfile");
  814. DWORD dwReturn=ERROR_INTERNAL_ERROR, dwErr,dwSize,dwType;
  815. HKEY hKeySID = NULL;
  816. WCHAR szNTUserPath[MAX_PATH];
  817. int cbNTUserPath = 0;
  818. PWCHAR pszSrc, pszDest;
  819. // find the ProfileImagePath
  820. //open the parent key
  821. dwErr = RegOpenKeyEx(hKeyProfileList,// handle to open key
  822. pszUserSID,// subkey name
  823. 0,// reserved
  824. KEY_READ,// security access mask
  825. &hKeySID);// handle to open key
  826. if (ERROR_SUCCESS != dwErr)
  827. {
  828. ErrorTrace(0,"Error %d in opening ProfileList of %S",
  829. dwErr, pszUserSID);
  830. dwReturn = dwErr;
  831. goto cleanup;
  832. }
  833. //now query for the profile image path
  834. {
  835. WCHAR szData[MAX_PATH];
  836. dwSize = sizeof(szData)/sizeof(WCHAR);
  837. dwType = REG_EXPAND_SZ;
  838. dwErr = RegQueryValueEx(hKeySID,// handle to key
  839. s_cszSnapshotProfileImagePath, // value name
  840. NULL, // reserved
  841. &dwType, // type buffer
  842. (LPBYTE) szData, // data buffer
  843. &dwSize);// size of data buffer
  844. if (ERROR_SUCCESS != dwErr)
  845. {
  846. ErrorTrace(0,"Error %d in querying Profilepath of %S", dwErr,
  847. pszUserSID);
  848. dwReturn = dwErr;
  849. goto cleanup;
  850. }
  851. if (0 == ExpandEnvironmentStrings( szData,
  852. szNTUserPath,
  853. sizeof(szNTUserPath)/sizeof(WCHAR)))
  854. {
  855. dwErr = GetLastError();
  856. ErrorTrace(0, "ExpandEnvironmentStrings failed for %S, ec=%d",
  857. szData, dwErr);
  858. if (ERROR_SUCCESS != dwErr)
  859. {
  860. dwReturn = dwErr;
  861. }
  862. goto cleanup;
  863. }
  864. cbNTUserPath = lstrlen(szNTUserPath);
  865. }
  866. {
  867. WCHAR szSnapshotPath[MAX_PATH];
  868. // save off the ntuser.dat into datastore
  869. lstrcat(szNTUserPath, L"\\");
  870. lstrcat(szNTUserPath, s_cszSnapshotNTUserDat);
  871. lstrcpy(pszNTUserPath, szNTUserPath);
  872. if (ERROR_SUCCESS!= CreateNTUserDatPath(
  873. szSnapshotPath,
  874. sizeof(szSnapshotPath)/sizeof(WCHAR),
  875. pszSnapshotDir, pszUserSID))
  876. {
  877. dwReturn=ERROR_INSUFFICIENT_BUFFER;
  878. goto cleanup;
  879. }
  880. if (fRestore == TRUE)
  881. {
  882. pszSrc=szSnapshotPath;
  883. pszDest=szNTUserPath;
  884. }
  885. else
  886. {
  887. pszSrc=szNTUserPath;
  888. pszDest=szSnapshotPath;
  889. }
  890. if (fRestore)
  891. {
  892. //
  893. // delete current ntuser.dat before putting old one back
  894. //
  895. if (FALSE == DeleteFile(pszDest))
  896. {
  897. ErrorTrace(0, "! DeleteFile on ntuser.dat : %ld", GetLastError());
  898. }
  899. else
  900. {
  901. DebugTrace(0, "NTuser.dat deleted");
  902. }
  903. }
  904. dwErr = SnapshotCopyFile(pszSrc, pszDest);
  905. if (ERROR_SUCCESS != dwErr)
  906. {
  907. dwReturn = dwErr;
  908. goto cleanup;
  909. }
  910. // save off the usrclass.dat also into datastore
  911. szNTUserPath[cbNTUserPath] = L'\0';
  912. lstrcat(szNTUserPath, L"\\");
  913. lstrcat(szNTUserPath, s_cszSnapshotUsrClassLocation);
  914. if (ERROR_SUCCESS!= CreateUsrClassPath(
  915. szSnapshotPath,
  916. sizeof(szSnapshotPath)/sizeof(WCHAR),
  917. pszSnapshotDir, pszUserSID))
  918. {
  919. dwReturn=ERROR_INSUFFICIENT_BUFFER;
  920. goto cleanup;
  921. }
  922. if (fRestore == TRUE)
  923. {
  924. pszSrc=szSnapshotPath;
  925. pszDest=szNTUserPath;
  926. }
  927. else
  928. {
  929. pszSrc=szNTUserPath;
  930. pszDest=szSnapshotPath;
  931. }
  932. if (fRestore)
  933. {
  934. //
  935. // delete current usrclass.dat before putting old one back
  936. //
  937. if (FALSE == DeleteFile(pszDest))
  938. {
  939. ErrorTrace(0, "! DeleteFile on usrclass.dat", GetLastError());
  940. }
  941. else
  942. {
  943. DebugTrace(0, "Usrclass.dat deleted");
  944. }
  945. }
  946. dwErr = SnapshotCopyFile(pszSrc, pszDest);
  947. if (ERROR_SUCCESS != dwErr)
  948. {
  949. // if we are here and the usrclass file could not be copied,
  950. // then we can ignore this error since the usrclass file may
  951. // not exist.
  952. DebugTrace(0, "UsrClass cannot be copied. ec=%d. Ignoring this error",
  953. dwErr);
  954. //dwReturn = dwErr;
  955. //goto cleanup;
  956. }
  957. }
  958. dwReturn = ERROR_SUCCESS;
  959. cleanup:
  960. if (NULL != hKeySID)
  961. {
  962. _VERIFY(ERROR_SUCCESS==RegCloseKey(hKeySID));
  963. }
  964. TraceFunctLeave();
  965. return dwReturn;
  966. }
  967. void CreateClassesKeyName( WCHAR * pszKeyName,
  968. WCHAR * pszUserSID)
  969. {
  970. wsprintf(pszKeyName, L"%s%s", pszUserSID, s_cszClassesKey);
  971. }
  972. DWORD ProcessUserRegKeys( WCHAR * pszUserSID,
  973. WCHAR * pszSnapshotDir,
  974. BOOL fRestore,
  975. WCHAR * pszOriginalFile)
  976. {
  977. TraceFunctEnter("ProcessUserRegKeys");
  978. DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
  979. LPWSTR szDest = new WCHAR[MAX_PATH];
  980. LPWSTR szKeyName = new WCHAR[MAX_PATH];
  981. if (!szDest || !szKeyName)
  982. {
  983. ErrorTrace(0, "Cannot allocate memory");
  984. dwReturn = ERROR_OUTOFMEMORY;
  985. goto cleanup;
  986. }
  987. if (ERROR_SUCCESS != CreateNTUserDatPath(szDest,
  988. MAX_PATH,
  989. pszSnapshotDir, pszUserSID))
  990. {
  991. dwReturn=ERROR_INSUFFICIENT_BUFFER;
  992. goto cleanup;
  993. }
  994. if (FALSE == fRestore)
  995. {
  996. dwErr = SaveRegKey(HKEY_USERS,
  997. pszUserSID, // Subkey to save
  998. szDest); // File to save in
  999. }
  1000. else
  1001. {
  1002. dwErr = SetNewRegistry(HKEY_USERS, // handle to open key
  1003. pszUserSID, // subkey name
  1004. szDest, // snapshot file
  1005. pszOriginalFile, // original file
  1006. pszSnapshotDir);
  1007. }
  1008. if (ERROR_SUCCESS != dwErr)
  1009. {
  1010. ErrorTrace(0, "SaveRegKey or SetNewRegistry failed ec=%d", dwErr);
  1011. dwReturn = dwErr;
  1012. goto cleanup;
  1013. }
  1014. if (ERROR_SUCCESS != CreateUsrClassPath(szDest,
  1015. MAX_PATH,
  1016. pszSnapshotDir, pszUserSID))
  1017. {
  1018. dwReturn=ERROR_INSUFFICIENT_BUFFER;
  1019. goto cleanup;
  1020. }
  1021. CreateClassesKeyName(szKeyName, pszUserSID);
  1022. if (FALSE == fRestore)
  1023. {
  1024. dwErr = SaveRegKey(HKEY_USERS,
  1025. szKeyName, // Subkey to save
  1026. szDest); // File to save in
  1027. }
  1028. else
  1029. {
  1030. dwErr = SetNewRegistry(HKEY_USERS, // handle to open key
  1031. szKeyName, // subkey name
  1032. szDest, // data file
  1033. pszOriginalFile,
  1034. pszSnapshotDir);
  1035. }
  1036. if (ERROR_SUCCESS != dwErr)
  1037. {
  1038. // if we are here and the usrclass file could not be copied,
  1039. // then we can ignore this error since the usrclass file may
  1040. // not exist.
  1041. DebugTrace(0, "UsrClass cannot be copied. ec=%d. Ignoring this error",
  1042. dwErr);
  1043. //dwReturn = dwErr;
  1044. //goto cleanup;
  1045. }
  1046. dwReturn = ERROR_SUCCESS;
  1047. cleanup:
  1048. if (szDest)
  1049. delete [] szDest;
  1050. if (szKeyName)
  1051. delete [] szKeyName;
  1052. TraceFunctLeave();
  1053. return dwReturn;
  1054. }
  1055. // the following function processes the HKeyUsers registry key
  1056. // if fRestore is TRUE it restores the registry key
  1057. // if fRestore is FALSE it snapshots the registry key
  1058. DWORD ProcessHKUsersKey( WCHAR * pszSnapshotDir,
  1059. IN HKEY hKeyHKLM,// handle to an open key from where
  1060. // Software\\Microsoft\\ can be read.
  1061. BOOL fRestore)
  1062. {
  1063. TraceFunctEnter("ProcessHKUsersKey");
  1064. WCHAR szSID[100];
  1065. DWORD dwReturn=ERROR_INTERNAL_ERROR, dwErr;
  1066. HKEY hKeyProfileList = NULL;
  1067. DWORD dwIndex,dwSize;
  1068. const WCHAR * pszProfileSubKeyName;
  1069. if (TRUE == fRestore)
  1070. {
  1071. // in this case this is a loaded hive of the system. We need
  1072. // to strip system from the subkey name to bew able to read
  1073. // this subkey.
  1074. pszProfileSubKeyName = s_cszSnapshotProfileList +
  1075. lstrlen(s_cszSoftwareHiveName) + 1;
  1076. }
  1077. else
  1078. {
  1079. pszProfileSubKeyName = s_cszSnapshotProfileList;
  1080. }
  1081. // open the ProfileList and enumerate
  1082. dwErr = RegOpenKeyEx( hKeyHKLM,// handle to open key
  1083. pszProfileSubKeyName,// subkey name
  1084. 0,// subkey name
  1085. KEY_READ,// security access mask
  1086. &hKeyProfileList);// handle to open key
  1087. if (ERROR_SUCCESS != dwErr)
  1088. {
  1089. ErrorTrace(0, "RegOpenKeyEx failed for ProfileList, error %ld", dwErr);
  1090. dwReturn = dwErr;
  1091. goto cleanup;
  1092. }
  1093. dwIndex = 0;
  1094. dwSize = sizeof(szSID)/sizeof(WCHAR);
  1095. while (ERROR_SUCCESS == (dwErr = RegEnumKeyEx( hKeyProfileList,
  1096. // handle to key to
  1097. // enumerate
  1098. dwIndex, // subkey index
  1099. szSID,// subkey name
  1100. &dwSize, // size of subkey
  1101. // buffer
  1102. NULL, // reserved
  1103. NULL, // class string buffer
  1104. NULL,// size of class
  1105. // string buffer
  1106. NULL)))// last write time
  1107. {
  1108. WCHAR szOriginalFile[MAX_PATH];
  1109. LPWSTR pszOriginalFile = NULL;
  1110. DebugTrace(0, "Enumerated Key %S", szSID);
  1111. dwIndex++;
  1112. // try to copy the file - if this fails we will try to save
  1113. // the reg key
  1114. lstrcpy(szOriginalFile, L"");
  1115. dwErr = CopyUserProfile(hKeyProfileList, szSID, pszSnapshotDir,
  1116. fRestore, szOriginalFile);
  1117. if (ERROR_SUCCESS != dwErr)
  1118. {
  1119. DebugTrace(0, "CopyUserProfile for %S failed. Error %d",
  1120. szSID, dwErr);
  1121. // The copy may have failed since the user profile may be
  1122. // currently loaded - try to use Registry functions for
  1123. // this purpose.
  1124. DebugTrace(0, "Trying registry APIs for %S", szSID);
  1125. if (0 == lstrcmp(szOriginalFile, L""))
  1126. pszOriginalFile = NULL;
  1127. else
  1128. pszOriginalFile = szOriginalFile;
  1129. dwErr = ProcessUserRegKeys(szSID, pszSnapshotDir, fRestore, pszOriginalFile);
  1130. if (ERROR_SUCCESS != dwErr)
  1131. {
  1132. ErrorTrace(0, "Error %d saving key %S - ignoring", dwErr, szSID);
  1133. //
  1134. // ignore error -- if profile was deleted by hand
  1135. // this could happen
  1136. // we will just bravely carry on
  1137. //
  1138. }
  1139. }
  1140. dwSize = sizeof(szSID)/sizeof(WCHAR);
  1141. }
  1142. {
  1143. WCHAR szDest[MAX_PATH];
  1144. // also save the .default key
  1145. if (ERROR_SUCCESS != CreateUsrDefaultPath(szDest,
  1146. sizeof(szDest)/sizeof(WCHAR),
  1147. pszSnapshotDir))
  1148. {
  1149. dwReturn=ERROR_INSUFFICIENT_BUFFER;
  1150. goto cleanup;
  1151. }
  1152. if (TRUE == fRestore)
  1153. {
  1154. dwErr = SetNewRegistry(HKEY_USERS, // handle to open key
  1155. s_cszSnapshotUsersDefaultKey, // subkey name
  1156. szDest, // data file
  1157. NULL,
  1158. NULL);
  1159. }
  1160. else
  1161. {
  1162. dwErr = SaveRegKey(HKEY_USERS,
  1163. s_cszSnapshotUsersDefaultKey,
  1164. szDest);
  1165. }
  1166. if (ERROR_SUCCESS != dwErr)
  1167. {
  1168. ErrorTrace(0, "Error processing default key ec=%d", dwErr);
  1169. dwReturn = dwErr;
  1170. _ASSERT(0);
  1171. goto cleanup;
  1172. }
  1173. }
  1174. dwReturn = ERROR_SUCCESS;
  1175. cleanup:
  1176. if (NULL != hKeyProfileList)
  1177. {
  1178. _VERIFY(ERROR_SUCCESS==RegCloseKey(hKeyProfileList));
  1179. }
  1180. TraceFunctLeave();
  1181. return dwReturn;
  1182. }
  1183. // the following function saves or restores a reg hive.
  1184. // if fRestore == TRUE it restores the reg hive
  1185. // if fRestore == FALSE it saves the reg hive
  1186. DWORD SnapshotRegHive(WCHAR * pszSnapshotDir,
  1187. WCHAR * pszHiveName)
  1188. {
  1189. TraceFunctEnter("SnapshotRegHive");
  1190. DWORD i,dwSnapDirLen, dwHivelen;
  1191. WCHAR szBackupFile[MAX_PATH];
  1192. DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
  1193. WCHAR * pszSubhiveName;
  1194. // first construct the name of the file to store the hive
  1195. wsprintf(szBackupFile, L"%s\\%s", pszSnapshotDir, pszHiveName);
  1196. // now replace all \ in the copy of pszHiveName to _
  1197. dwSnapDirLen=lstrlen(pszSnapshotDir)+1; // +1 is for the \\ after
  1198. //pszSnapshotDir
  1199. dwHivelen = lstrlen(pszHiveName);
  1200. for (i=dwSnapDirLen; i< dwHivelen+ dwSnapDirLen; i++)
  1201. {
  1202. if (szBackupFile[i] == L'\\')
  1203. {
  1204. szBackupFile[i] = L'_';
  1205. }
  1206. }
  1207. // figure out if it is the HKLM hive - we already snapshot the HK
  1208. // users hive
  1209. if (0 != _wcsnicmp( pszHiveName, s_cszHKLMPrefix,lstrlen(s_cszHKLMPrefix)))
  1210. {
  1211. DebugTrace(0, "%S is not a HKLM hive", pszHiveName);
  1212. dwReturn = ERROR_SUCCESS;
  1213. goto cleanup;
  1214. }
  1215. // get the hive name
  1216. pszSubhiveName = pszHiveName + lstrlen(s_cszHKLMPrefix);
  1217. // now check to see if the hive is one that we have created
  1218. // ourselves. If so, ignore this hive
  1219. if ( (lstrcmpi(pszSubhiveName,s_cszRestoreSAMHiveName)==0) ||
  1220. (lstrcmpi(pszSubhiveName,s_cszRestoreSYSTEMHiveName)==0) ||
  1221. (lstrcmpi(pszSubhiveName,s_cszRestoreSECURITYHiveName)==0) )
  1222. {
  1223. DebugTrace(0, "Ignoring %S since it a hive created by restore",
  1224. pszSubhiveName);
  1225. dwReturn = ERROR_SUCCESS;
  1226. goto cleanup;
  1227. }
  1228. dwErr = SaveRegKey(HKEY_LOCAL_MACHINE,
  1229. pszSubhiveName,
  1230. szBackupFile);
  1231. if (ERROR_SUCCESS != dwErr)
  1232. {
  1233. ErrorTrace(0, "SaveRegKey failed for HiveList, ec=%ld", dwErr);
  1234. // now check to see if this is a well known HKLM hive. If not, ignore any errors in
  1235. // snapshotting this hive
  1236. if (FALSE==IsWellKnownHKLMHive(pszSubhiveName))
  1237. {
  1238. dwReturn=ERROR_SUCCESS;
  1239. }
  1240. else
  1241. {
  1242. dwReturn = dwErr;
  1243. }
  1244. goto cleanup;
  1245. }
  1246. dwReturn = ERROR_SUCCESS;
  1247. cleanup:
  1248. // call reg save key on this
  1249. TraceFunctLeave();
  1250. return dwReturn;
  1251. }
  1252. // the following function does processing of the HKLM key. It does it
  1253. // by reading the hives listed in the reg key
  1254. // System\\CurrentControlSet\\Control\\Hivelist. It ignores the Users
  1255. // subkeys.
  1256. DWORD DoHKLMSnapshot(IN WCHAR * pszSnapshotDir)
  1257. {
  1258. TraceFunctEnter("DoHKLMSnapshot");
  1259. DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
  1260. HKEY hKeyHiveList=NULL;
  1261. WCHAR szHiveName[MAX_PATH], szDataValue[MAX_PATH];
  1262. DWORD dwSize, dwValueIndex, dwDataSize;
  1263. const WCHAR * pszHiveSubKeyName;
  1264. // open the ProfileList and enumerate
  1265. dwErr = RegOpenKeyEx( HKEY_LOCAL_MACHINE,// handle to open key
  1266. s_cszSnapshotHiveList,// Subkey name
  1267. 0,// options
  1268. KEY_READ,// security access mask
  1269. &hKeyHiveList);// handle to open key
  1270. if (ERROR_SUCCESS != dwErr)
  1271. {
  1272. ErrorTrace(0, "RegOpenKeyEx failed for HiveList, ec=%ld", dwErr);
  1273. dwReturn = dwErr;
  1274. goto cleanup;
  1275. }
  1276. for (dwValueIndex = 0; TRUE; dwValueIndex ++)
  1277. {
  1278. dwSize = sizeof(szHiveName)/sizeof(WCHAR);
  1279. dwDataSize = sizeof(szDataValue); // this is in bytes
  1280. dwErr= RegEnumValue(hKeyHiveList, // handle to key to query
  1281. dwValueIndex, // index of value to query
  1282. szHiveName, // value buffer
  1283. &dwSize, // size of value buffer
  1284. NULL, // reserved
  1285. NULL, // type buffer
  1286. (PBYTE)szDataValue, // data buffer
  1287. &dwDataSize); // size of data buffer
  1288. if (ERROR_SUCCESS != dwErr)
  1289. {
  1290. _ASSERT(ERROR_NO_MORE_ITEMS == dwErr);
  1291. break;
  1292. }
  1293. // if the hive does not have a data file, do not back it up.
  1294. if (lstrlen(szDataValue) == 0)
  1295. {
  1296. DebugTrace(0, "There is no data for hive %S. Ignoring",
  1297. szHiveName);
  1298. continue;
  1299. }
  1300. dwErr = SnapshotRegHive(pszSnapshotDir, szHiveName);
  1301. if (ERROR_SUCCESS != dwErr)
  1302. {
  1303. ErrorTrace(0, "Processing failed for Hive %S, ec=%ld",
  1304. szHiveName, dwErr);
  1305. dwReturn = dwErr;
  1306. goto cleanup;
  1307. }
  1308. }
  1309. dwReturn = ERROR_SUCCESS;
  1310. cleanup:
  1311. if (NULL != hKeyHiveList)
  1312. {
  1313. _VERIFY(ERROR_SUCCESS==RegCloseKey(hKeyHiveList));
  1314. }
  1315. TraceFunctLeave();
  1316. return dwReturn;
  1317. }
  1318. DWORD
  1319. CSnapshot::DoRegistrySnapshot(WCHAR * pszSnapshotDir)
  1320. {
  1321. DWORD dwErr, dwReturn = ERROR_INTERNAL_ERROR;
  1322. TraceFunctEnter("CSnapshot::DoRegistrySnapshot");
  1323. dwErr = ProcessHKUsersKey(pszSnapshotDir, HKEY_LOCAL_MACHINE,
  1324. FALSE); // need to do a snapshot
  1325. if (ERROR_SUCCESS != dwErr)
  1326. {
  1327. ErrorTrace(0, "DoHKUsersSnapshot failed error %ld", dwErr);
  1328. dwReturn = dwErr;
  1329. goto cleanup;
  1330. }
  1331. // now snapshot other hives also
  1332. dwErr = DoHKLMSnapshot(pszSnapshotDir);
  1333. if (ERROR_SUCCESS != dwErr)
  1334. {
  1335. ErrorTrace(0, "DoHKLMSnapshot failed error %ld", dwErr);
  1336. dwReturn = dwErr;
  1337. goto cleanup;
  1338. }
  1339. dwReturn = ERROR_SUCCESS;
  1340. cleanup:
  1341. TraceFunctLeave();
  1342. return dwReturn;
  1343. }
  1344. DWORD CSnapshot::GetCOMplusBackupFN(HMODULE hCOMDll)
  1345. {
  1346. TraceFunctEnter("CSnapshot::GetCOMplusBackupFN");
  1347. DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
  1348. if (NULL == hCOMDll)
  1349. {
  1350. goto cleanup;
  1351. }
  1352. // now get the address of the Backup functions
  1353. m_pfnRegDbBackup = (PF_REG_DB_API)GetProcAddress(hCOMDll,
  1354. s_cszRegDBBackupFn);
  1355. if (NULL == m_pfnRegDbBackup)
  1356. {
  1357. dwErr = GetLastError();
  1358. ErrorTrace(0, "Error getting function RegDBBackup. ec=%d", dwErr);
  1359. if (ERROR_SUCCESS != dwErr)
  1360. {
  1361. dwReturn = dwErr;
  1362. }
  1363. goto cleanup;
  1364. }
  1365. dwReturn= ERROR_SUCCESS;
  1366. cleanup:
  1367. TraceFunctLeave();
  1368. return dwReturn;
  1369. }
  1370. DWORD CSnapshot::GetCOMplusRestoreFN()
  1371. {
  1372. TraceFunctEnter("CSnapshot::GetCOMplusRestoreFN");
  1373. DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
  1374. // first load the COM+ dll
  1375. if (NULL == m_hRegdbDll)
  1376. {
  1377. m_hRegdbDll = LoadLibrary(s_cszCOMDllName);
  1378. if (NULL == m_hRegdbDll)
  1379. {
  1380. dwReturn = GetLastError();
  1381. trace(0, "LoadLibrary of %S failed ec=%d", s_cszCOMDllName, dwReturn);
  1382. goto cleanup;
  1383. }
  1384. }
  1385. // now get the address of the Backup functions
  1386. m_pfnRegDbRestore = (PF_REG_DB_API)GetProcAddress(m_hRegdbDll,
  1387. s_cszRegDBRestoreFn);
  1388. if (NULL == m_pfnRegDbRestore)
  1389. {
  1390. dwErr = GetLastError();
  1391. ErrorTrace(0, "Error getting function RegDBRestore. ec=%d", dwErr);
  1392. if (ERROR_SUCCESS != dwErr)
  1393. {
  1394. dwReturn = dwErr;
  1395. }
  1396. goto cleanup;
  1397. }
  1398. dwReturn= ERROR_SUCCESS;
  1399. cleanup:
  1400. TraceFunctLeave();
  1401. return dwReturn;
  1402. }
  1403. void CreateCOMDBSnapShotFileName( WCHAR * pszSnapshotDir,
  1404. WCHAR * pszCOMDBFile )
  1405. {
  1406. wsprintf(pszCOMDBFile, L"%s\\%s", pszSnapshotDir, s_cszCOMDBBackupFile);
  1407. return;
  1408. }
  1409. DWORD
  1410. CSnapshot::DoCOMDbSnapshot(WCHAR * pszSnapshotDir, HMODULE hCOMDll)
  1411. {
  1412. TraceFunctEnter("CSnapshot::DoCOMDbSnapshot");
  1413. DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
  1414. HMODULE hModCOMDll=NULL;
  1415. HRESULT hr;
  1416. WCHAR szCOMDBFile[MAX_PATH];
  1417. if (NULL == m_pfnRegDbBackup)
  1418. {
  1419. dwErr = GetCOMplusBackupFN(hCOMDll);
  1420. if (ERROR_SUCCESS != dwErr)
  1421. {
  1422. dwReturn = dwErr;
  1423. goto cleanup;
  1424. }
  1425. }
  1426. // construct the path of the database backup file
  1427. CreateCOMDBSnapShotFileName(pszSnapshotDir, szCOMDBFile);
  1428. hr =m_pfnRegDbBackup( szCOMDBFile );
  1429. // call the function to backup the file
  1430. if ( FAILED(hr))
  1431. {
  1432. ErrorTrace(0, "Failed to snapshot COM DB. hr=0x%x", hr);
  1433. goto cleanup;
  1434. }
  1435. dwReturn = ERROR_SUCCESS;
  1436. cleanup:
  1437. TraceFunctLeave();
  1438. return dwReturn;
  1439. }
  1440. void CreateWMISnapShotFileName( WCHAR * pszSnapshotDir,
  1441. WCHAR * pszWMIBackupFile )
  1442. {
  1443. wsprintf(pszWMIBackupFile, L"%s\\%s", pszSnapshotDir,
  1444. s_cszWMIBackupFile);
  1445. return;
  1446. }
  1447. DWORD DoWMISnapshot(VOID * pParam)
  1448. {
  1449. TraceFunctEnter("DoWMISnapshot");
  1450. WMISnapshotParam * pwsp = (WMISnapshotParam *) pParam;
  1451. DWORD dwErr = ERROR_SUCCESS;
  1452. HRESULT hr = S_OK;
  1453. WCHAR szWMIBackupFile[MAX_PATH];
  1454. WCHAR szWMIRepository[MAX_PATH];
  1455. IWbemBackupRestoreEx *wbem ;
  1456. BOOL fCoInitialized = FALSE;
  1457. CTokenPrivilege tp;
  1458. BOOL fHaveLock = FALSE;
  1459. BOOL fSerialized = TRUE;
  1460. if (NULL == pwsp)
  1461. {
  1462. ErrorTrace(0, "pwsp=NULL");
  1463. TraceFunctLeave();
  1464. dwErr = ERROR_INVALID_PARAMETER;
  1465. return dwErr;
  1466. }
  1467. fSerialized = pwsp->fSerialized;
  1468. dwErr = tp.SetPrivilegeInAccessToken(SE_BACKUP_NAME);
  1469. if (ERROR_SUCCESS != dwErr)
  1470. {
  1471. ErrorTrace(0, "SetPrivilegeInAccessToken failed ec=%d", dwErr);
  1472. dwErr = ERROR_PRIVILEGE_NOT_HELD;
  1473. goto cleanup;
  1474. }
  1475. hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
  1476. if (hr == RPC_E_CHANGED_MODE)
  1477. {
  1478. //
  1479. // someone called it with other mode
  1480. //
  1481. hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );
  1482. }
  1483. if (FAILED(hr))
  1484. {
  1485. dwErr = (DWORD) hr;
  1486. ErrorTrace(0, "! CoInitializeEx : %ld", dwErr);
  1487. goto cleanup;
  1488. }
  1489. fCoInitialized = TRUE;
  1490. // construct the path of the database backup file
  1491. CreateWMISnapShotFileName(pwsp->szSnapshotDir, szWMIBackupFile);
  1492. GetSystemDirectory (szWMIRepository, MAX_PATH);
  1493. lstrcatW (szWMIRepository, L"\\Wbem\\Repository");
  1494. if ( SUCCEEDED(CoCreateInstance( CLSID_WbemBackupRestore,
  1495. NULL,
  1496. CLSCTX_LOCAL_SERVER,
  1497. IID_IWbemBackupRestoreEx,
  1498. (LPVOID*)&wbem )) )
  1499. {
  1500. if (FAILED(hr = CoSetProxyBlanket (wbem,
  1501. RPC_C_AUTHN_DEFAULT,
  1502. RPC_C_AUTHZ_DEFAULT,
  1503. COLE_DEFAULT_PRINCIPAL,
  1504. RPC_C_AUTHN_LEVEL_CONNECT,
  1505. RPC_C_IMP_LEVEL_IMPERSONATE,
  1506. NULL,
  1507. EOAC_DYNAMIC_CLOAKING)))
  1508. {
  1509. TRACE(0, "CoSetProxyBlanket failed ignoring %x ", hr);
  1510. }
  1511. if (SUCCEEDED(hr = wbem->Pause()))
  1512. {
  1513. // signal to main thread that pause is done
  1514. if (pwsp->hEvent != NULL)
  1515. {
  1516. SetEvent (pwsp->hEvent);
  1517. }
  1518. // get the datastore lock
  1519. if (g_pEventHandler)
  1520. {
  1521. fHaveLock = g_pEventHandler->GetLock()->Lock(CLock::TIMEOUT);
  1522. if (! fHaveLock)
  1523. {
  1524. trace(0, "Cannot get lock");
  1525. dwErr = ERROR_INTERNAL_ERROR;
  1526. wbem->Resume();
  1527. wbem->Release();
  1528. goto cleanup;
  1529. }
  1530. }
  1531. // do the main wmi snapshotting
  1532. if (FALSE == CreateDirectoryW (szWMIBackupFile, NULL))
  1533. {
  1534. dwErr = GetLastError();
  1535. if (ERROR_ALREADY_EXISTS != dwErr)
  1536. {
  1537. ErrorTrace(0, "Failed to create repository dir. LastError=%d", dwErr);
  1538. }
  1539. else dwErr = ERROR_SUCCESS;
  1540. }
  1541. if (ERROR_SUCCESS == dwErr)
  1542. dwErr = CopyFile_Recurse (szWMIRepository, szWMIBackupFile);
  1543. hr = wbem->Resume();
  1544. if ( FAILED(hr))
  1545. {
  1546. ErrorTrace(0, "Failed to resume WMI DB. ignoring hr=0x%x", hr);
  1547. }
  1548. }
  1549. else
  1550. {
  1551. ErrorTrace(0, "Failed to pause WMI DB. ignoring hr=0x%x", hr);
  1552. // signal to main thread anyway
  1553. if (pwsp->hEvent != NULL)
  1554. {
  1555. SetEvent (pwsp->hEvent);
  1556. }
  1557. if (g_pEventHandler)
  1558. {
  1559. fHaveLock = g_pEventHandler->GetLock()->Lock(CLock::TIMEOUT);
  1560. if (! fHaveLock)
  1561. {
  1562. trace(0, "Cannot get lock with WMI Pause failed");
  1563. dwErr = ERROR_INTERNAL_ERROR;
  1564. wbem->Release();
  1565. goto cleanup;
  1566. }
  1567. }
  1568. }
  1569. wbem->Release() ;
  1570. }
  1571. cleanup:
  1572. if (pwsp->hEvent != NULL)
  1573. {
  1574. CloseHandle (pwsp->hEvent);
  1575. pwsp->hEvent = NULL;
  1576. }
  1577. if (fCoInitialized)
  1578. CoUninitialize();
  1579. // now calculate accurate complete size of old restore point
  1580. // and snapshot size of current restore point
  1581. if (g_pDataStoreMgr && fHaveLock)
  1582. {
  1583. dwErr = g_pDataStoreMgr->GetDriveTable()->
  1584. ForAllDrives(&CDataStore::SwitchRestorePoint,
  1585. (LONG_PTR) pwsp->pRpLast);
  1586. if (dwErr != ERROR_SUCCESS)
  1587. {
  1588. trace(0, "! SwitchRestorePoint : %ld", dwErr);
  1589. }
  1590. // if this is parallelized, then check fifo conditions here
  1591. // else check it in SRSetRestorePointS
  1592. if (! pwsp->fSerialized)
  1593. {
  1594. g_pDataStoreMgr->TriggerFreezeOrFifo();
  1595. }
  1596. }
  1597. if (pwsp)
  1598. {
  1599. if (pwsp->pRpLast)
  1600. delete pwsp->pRpLast;
  1601. delete pwsp;
  1602. pwsp = NULL;
  1603. trace(0, "DoWMISnapshot released pwsp");
  1604. }
  1605. // release the datastore lock
  1606. if (fHaveLock)
  1607. {
  1608. if (g_pEventHandler)
  1609. g_pEventHandler->GetLock()->Unlock();
  1610. }
  1611. if (! fSerialized && g_pEventHandler)
  1612. g_pEventHandler->GetCounter()->Down();
  1613. TraceFunctLeave();
  1614. return dwErr;
  1615. }
  1616. DWORD RestoreWMISnapshot(WCHAR * pszSnapshotDir)
  1617. {
  1618. TraceFunctEnter("RestoreWMISnapshot");
  1619. IWbemBackupRestoreEx *wbem = NULL;
  1620. DWORD dwErr = ERROR_SUCCESS;
  1621. HRESULT hr = S_OK;
  1622. BOOL fPaused = FALSE;
  1623. WCHAR szWMIBackupFile[MAX_PATH];
  1624. WCHAR szWMIRepository[MAX_PATH];
  1625. WCHAR szWMITemp[MAX_PATH];
  1626. CTokenPrivilege tp;
  1627. // construct the path of the database backup file
  1628. CreateWMISnapShotFileName(pszSnapshotDir, szWMIBackupFile);
  1629. GetSystemDirectory (szWMIRepository, MAX_PATH);
  1630. lstrcpyW (szWMITemp, szWMIRepository);
  1631. lstrcatW (szWMIRepository, L"\\Wbem\\Repository");
  1632. lstrcatW (szWMITemp, L"\\Wbem\\Repository.tmp");
  1633. Delnode_Recurse (szWMITemp, TRUE, NULL); // delete previous temp dirs
  1634. if (FALSE == CreateDirectoryW (szWMITemp, NULL))
  1635. {
  1636. dwErr = GetLastError();
  1637. if (dwErr != ERROR_ALREADY_EXISTS)
  1638. {
  1639. ErrorTrace(0, "Failed to create WMI temp dir. Ignoring error=0x%x", dwErr);
  1640. dwErr = ERROR_SUCCESS;
  1641. goto cleanup;
  1642. }
  1643. dwErr = ERROR_SUCCESS;
  1644. }
  1645. dwErr = CopyFile_Recurse (szWMIBackupFile, szWMITemp);
  1646. if (ERROR_SUCCESS != dwErr)
  1647. {
  1648. ErrorTrace(0, "Failed CopyFile_Recurse. Ignoring error=0x%x", dwErr);
  1649. dwErr = ERROR_SUCCESS;
  1650. Delnode_Recurse (szWMITemp, TRUE, NULL);
  1651. goto cleanup;
  1652. }
  1653. lstrcpyW (szWMIBackupFile, szWMIRepository);
  1654. lstrcatW (szWMIBackupFile, L".bak");
  1655. // If WMI is still running, try to stop it
  1656. if ( SUCCEEDED(hr = CoCreateInstance( CLSID_WbemBackupRestore,
  1657. NULL,
  1658. CLSCTX_LOCAL_SERVER,
  1659. IID_IWbemBackupRestoreEx,
  1660. (LPVOID*)&wbem )) )
  1661. {
  1662. tp.SetPrivilegeInAccessToken(SE_BACKUP_NAME);
  1663. fPaused = SUCCEEDED(hr = wbem->Pause());
  1664. if (FAILED(hr))
  1665. TRACE(0, "Wbem Pause failed ignoring %x", hr);
  1666. }
  1667. else
  1668. {
  1669. TRACE(0, "CoCreateInstance failed ignoring %x", hr);
  1670. }
  1671. Delnode_Recurse (szWMIBackupFile, TRUE, NULL); // delete leftover backups
  1672. if (FALSE == MoveFile(szWMIRepository, szWMIBackupFile))
  1673. {
  1674. dwErr = GetLastError();
  1675. ErrorTrace(0, "! MoveFile : %ld trying SrMoveFileEx", dwErr);
  1676. // WMI has locked files, so try SrMoveFileEx
  1677. dwErr = SrMoveFileEx(pszSnapshotDir, szWMIRepository, szWMIBackupFile);
  1678. if (ERROR_SUCCESS == dwErr)
  1679. {
  1680. dwErr = SrMoveFileEx(pszSnapshotDir, szWMITemp, szWMIRepository);
  1681. if (ERROR_SUCCESS != dwErr)
  1682. ErrorTrace(0, "! SRMoveFileEx : %ld", dwErr);
  1683. }
  1684. else
  1685. {
  1686. ErrorTrace(0, "! SRMoveFileEx : %ld", dwErr);
  1687. Delnode_Recurse (szWMITemp, TRUE, NULL);
  1688. }
  1689. goto cleanup;
  1690. }
  1691. if (FALSE == MoveFile(szWMITemp, szWMIRepository))
  1692. {
  1693. dwErr = GetLastError();
  1694. ErrorTrace(0, "! MoveFile : %ld", dwErr);
  1695. goto cleanup;
  1696. }
  1697. Delnode_Recurse (szWMIBackupFile, TRUE, NULL);
  1698. cleanup:
  1699. if (wbem != NULL)
  1700. {
  1701. if (fPaused)
  1702. wbem->Resume();
  1703. wbem->Release();
  1704. }
  1705. TraceFunctLeave();
  1706. return dwErr;
  1707. }
  1708. DWORD DoIISSnapshot(WCHAR * pszSnapshotDir)
  1709. {
  1710. TraceFunctEnter("DoIISSnapshot");
  1711. DWORD dwReturn=ERROR_INTERNAL_ERROR;
  1712. HRESULT hr;
  1713. WCHAR szRestorePath[MAX_PATH], szBackup[MAX_PATH], szTemp[MAX_PATH];
  1714. IMSAdminBase2W *pims = NULL;
  1715. // construct the path of the database backup file
  1716. wsprintf(szRestorePath, L"%s\\%s", pszSnapshotDir, s_cszIISBackupFile);
  1717. hr = CoCreateInstance( CLSID_MSAdminBase_W,
  1718. NULL,
  1719. CLSCTX_ALL,
  1720. IID_IMSAdminBase2_W,
  1721. (LPVOID*)&pims);
  1722. if (FAILED(hr))
  1723. {
  1724. ErrorTrace(0, "! CoCreateInstance : 0x%x - ignoring error", hr);
  1725. dwReturn = ERROR_SUCCESS;
  1726. goto cleanup;
  1727. }
  1728. hr = pims->BackupWithPasswd(s_cszIISBackupFile,
  1729. MD_BACKUP_MAX_VERSION,
  1730. MD_BACKUP_OVERWRITE | MD_BACKUP_SAVE_FIRST | MD_BACKUP_FORCE_BACKUP,
  1731. NULL);
  1732. pims->Release() ;
  1733. if (FAILED(hr))
  1734. {
  1735. ErrorTrace(0, "! BackupWithPasswd : 0x%x", hr);
  1736. dwReturn = (DWORD) hr;
  1737. goto cleanup;
  1738. }
  1739. //
  1740. // move the file from their backup to our backup
  1741. //
  1742. if (0 == ExpandEnvironmentStrings(s_cszIISBackupPath, szTemp, MAX_PATH))
  1743. {
  1744. dwReturn = GetLastError();
  1745. ErrorTrace(0, "! ExpandEnvironmentStrings : %ld", dwReturn);
  1746. goto cleanup;
  1747. }
  1748. wsprintf(szBackup, L"%s%s%s%d", szTemp, s_cszIISBackupFile, s_cszIISSuffix, MD_BACKUP_MAX_VERSION);
  1749. if (FALSE == MoveFile(szBackup, szRestorePath))
  1750. {
  1751. dwReturn = GetLastError();
  1752. ErrorTrace(0, "! MoveFile : %ld", dwReturn);
  1753. goto cleanup;
  1754. }
  1755. dwReturn = ERROR_SUCCESS;
  1756. cleanup:
  1757. TraceFunctLeave();
  1758. return dwReturn;
  1759. }
  1760. DWORD RestoreIISSnapshot(WCHAR * pszSnapshotDir)
  1761. {
  1762. TraceFunctEnter("RestoreIISSnapshot");
  1763. DWORD dwReturn=ERROR_INTERNAL_ERROR;
  1764. HRESULT hr;
  1765. WCHAR szRestorePath[MAX_PATH], szDest[MAX_PATH];
  1766. IMSAdminBase2W *pims = NULL;
  1767. // construct the path of the database backup file
  1768. wsprintf(szRestorePath, L"%s\\%s", pszSnapshotDir, s_cszIISBackupFile);
  1769. //
  1770. // if we don't have the file
  1771. // there is nothing to restore
  1772. //
  1773. if (0xFFFFFFFF == GetFileAttributes(szRestorePath))
  1774. {
  1775. DebugTrace(0, "IIS snapshot does not exist");
  1776. dwReturn = ERROR_SUCCESS;
  1777. goto cleanup;
  1778. }
  1779. //
  1780. // copy the file from our backup to their original location -
  1781. // we can do a simple copy here because IIS should be shutdown
  1782. // at this time
  1783. //
  1784. if (0 == ExpandEnvironmentStrings(s_cszIISOriginalPath, szDest, MAX_PATH))
  1785. {
  1786. dwReturn = GetLastError();
  1787. ErrorTrace(0, "! ExpandEnvironmentStrings : %ld", dwReturn);
  1788. goto cleanup;
  1789. }
  1790. if (ERROR_SUCCESS != (dwReturn = SnapshotCopyFile(szRestorePath, szDest)))
  1791. {
  1792. ErrorTrace(0, "! SnapshotCopyFile : %ld", dwReturn);
  1793. goto cleanup;
  1794. }
  1795. dwReturn = ERROR_SUCCESS;
  1796. cleanup:
  1797. TraceFunctLeave();
  1798. return dwReturn;
  1799. }
  1800. DWORD
  1801. SnapshotRestoreFilelistFiles(LPWSTR pszSnapshotDir, BOOL fSnapshot)
  1802. {
  1803. TraceFunctEnter("SnapshotRestoreFilelistFiles");
  1804. DWORD dwErr = ERROR_SUCCESS;
  1805. DWORD dwIndex, dwDataSize, dwSize;
  1806. LPWSTR pszFilePart = NULL ;
  1807. HKEY hKey = NULL;
  1808. BOOL fLoaded = FALSE;
  1809. if (fSnapshot == FALSE) // restore
  1810. {
  1811. //
  1812. // load the software hive of the registry to be restored
  1813. //
  1814. WCHAR szSoftwareHive[MAX_PATH];
  1815. wsprintf(szSoftwareHive,
  1816. L"%s\\%s%s",
  1817. pszSnapshotDir,
  1818. s_cszHKLMFilePrefix,
  1819. s_cszSoftwareHiveName);
  1820. CHECKERR( RegLoadKey(HKEY_LOCAL_MACHINE,
  1821. LOAD_KEY_NAME,
  1822. szSoftwareHive),
  1823. L"RegLoadKey" );
  1824. fLoaded = TRUE;
  1825. }
  1826. {
  1827. WCHAR szCallbacksKey[MAX_PATH];
  1828. wsprintf(szCallbacksKey,
  1829. L"%s\\%s\\%s",
  1830. fSnapshot ? L"Software" : LOAD_KEY_NAME,
  1831. s_cszSRRegKey2, s_cszCallbacksRegKey);
  1832. DebugTrace(0, "CallbacksKey=%S", szCallbacksKey);
  1833. //
  1834. // call registered snapshot callbacks
  1835. //
  1836. dwErr = CallSnapshotCallbacks(szCallbacksKey, pszSnapshotDir, fSnapshot);
  1837. if (dwErr != ERROR_SUCCESS)
  1838. {
  1839. ErrorTrace(0, "! CallSnapshotCallbacks : %ld - ignoring", dwErr);
  1840. }
  1841. }
  1842. {
  1843. WCHAR szSnapshotKey[MAX_PATH];
  1844. wsprintf(szSnapshotKey,
  1845. L"%s\\%s\\%s",
  1846. fSnapshot ? L"Software" : LOAD_KEY_NAME,
  1847. s_cszSRRegKey2, s_cszSRSnapshotRegKey);
  1848. DebugTrace(0, "SnapshotFilesKey=%S", szSnapshotKey);
  1849. dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1850. szSnapshotKey,
  1851. 0,
  1852. KEY_READ,
  1853. &hKey);
  1854. if (dwErr != ERROR_SUCCESS) // assume key does not exist
  1855. {
  1856. dwErr = ERROR_SUCCESS;
  1857. DebugTrace(0, "No filelist files to snapshot/restore");
  1858. goto Err;
  1859. }
  1860. }
  1861. for (dwIndex = 0; TRUE; dwIndex ++)
  1862. {
  1863. WCHAR szValue[MAX_PATH], szDest[MAX_PATH], szFile[MAX_PATH];
  1864. dwSize = sizeof(szValue)/sizeof(WCHAR);
  1865. dwDataSize = sizeof(szFile); // this is in bytes
  1866. dwErr = RegEnumValue(hKey, // handle to key to query
  1867. dwIndex, // index of value to query
  1868. szValue, // value buffer
  1869. &dwSize, // size of value buffer
  1870. NULL, // reserved
  1871. NULL, // type buffer
  1872. (PBYTE) szFile, // data buffer
  1873. &dwDataSize); // size of data buffer
  1874. if (ERROR_SUCCESS != dwErr)
  1875. {
  1876. break;
  1877. }
  1878. if (lstrlen(szFile) == 0)
  1879. {
  1880. continue;
  1881. }
  1882. //
  1883. // construct snapshot file path
  1884. // make a unique name for it by appending the enum index
  1885. //
  1886. pszFilePart = wcsrchr(szFile, L'\\');
  1887. if (pszFilePart)
  1888. {
  1889. pszFilePart++;
  1890. }
  1891. else
  1892. {
  1893. pszFilePart = szFile;
  1894. }
  1895. wsprintf(szDest, L"%s\\%s-%d", pszSnapshotDir, pszFilePart, dwIndex);
  1896. //
  1897. // copy the file
  1898. // if file does not exist, keep going
  1899. //
  1900. if (fSnapshot) // from orig location to snapshot dir
  1901. {
  1902. SnapshotCopyFile(szFile, szDest);
  1903. }
  1904. else // from snapshot dir to orig location
  1905. {
  1906. SnapshotCopyFile(szDest, szFile);
  1907. }
  1908. }
  1909. if (ERROR_NO_MORE_ITEMS == dwErr)
  1910. {
  1911. dwErr = ERROR_SUCCESS;
  1912. }
  1913. else
  1914. {
  1915. ErrorTrace(0, "! RegEnumValue : %ld", dwErr);
  1916. }
  1917. Err:
  1918. if (hKey)
  1919. RegCloseKey(hKey);
  1920. if (fLoaded)
  1921. RegUnLoadKey( HKEY_LOCAL_MACHINE, LOAD_KEY_NAME );
  1922. TraceFunctLeave();
  1923. return dwErr;
  1924. }
  1925. DWORD CTokenPrivilege::SetPrivilegeInAccessToken(WCHAR * pszPrivilegeName)
  1926. {
  1927. TraceFunctEnter("CSnapshot::SetPrivilegeInAccessToken");
  1928. HANDLE hProcess;
  1929. HANDLE hAccessToken=NULL;
  1930. LUID luidPrivilegeLUID;
  1931. TOKEN_PRIVILEGES tpTokenPrivilege; // enough for 1 priv
  1932. DWORD dwErr = ERROR_SUCCESS;
  1933. hProcess = GetCurrentProcess();
  1934. if (!hProcess)
  1935. {
  1936. dwErr = GetLastError();
  1937. ErrorTrace(0, "GetCurrentProcess failed ec=%d", dwErr);
  1938. goto done;
  1939. }
  1940. //
  1941. // If there is a thread token, attempt to use it first
  1942. //
  1943. if (!OpenThreadToken (GetCurrentThread(),
  1944. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  1945. TRUE, // check against process's security context
  1946. &hAccessToken))
  1947. {
  1948. if (!OpenProcessToken(hProcess,
  1949. TOKEN_DUPLICATE | TOKEN_QUERY,
  1950. &hAccessToken))
  1951. {
  1952. dwErr=GetLastError();
  1953. ErrorTrace(0, "OpenProcessToken failed ec=%d", dwErr);
  1954. goto done;
  1955. }
  1956. HANDLE hNewToken; // dup the process token to workaround RPC problem
  1957. if (FALSE == DuplicateTokenEx (hAccessToken,
  1958. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_IMPERSONATE,
  1959. NULL, SecurityImpersonation,
  1960. TokenImpersonation, &hNewToken))
  1961. {
  1962. dwErr=GetLastError();
  1963. ErrorTrace(0, "DuplicateTokenEx failed ec=%d", dwErr);
  1964. goto done;
  1965. }
  1966. CloseHandle (hAccessToken); // close the old process token
  1967. hAccessToken = hNewToken; // use the new thread token
  1968. if (TRUE == SetThreadToken (NULL, hAccessToken))
  1969. {
  1970. m_fNewToken = TRUE;
  1971. }
  1972. else
  1973. {
  1974. dwErr = GetLastError();
  1975. ErrorTrace(0, "SetThreadToken failed ec=%d", dwErr);
  1976. goto done;
  1977. }
  1978. }
  1979. if (!LookupPrivilegeValue(NULL,
  1980. pszPrivilegeName,
  1981. &luidPrivilegeLUID))
  1982. {
  1983. dwErr=GetLastError();
  1984. ErrorTrace(0, "LookupPrivilegeValue failed ec=%d",dwErr);
  1985. goto done;
  1986. }
  1987. tpTokenPrivilege.PrivilegeCount = 1;
  1988. tpTokenPrivilege.Privileges[0].Luid = luidPrivilegeLUID;
  1989. tpTokenPrivilege.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  1990. if (!AdjustTokenPrivileges(hAccessToken,
  1991. FALSE, // Do not disable all
  1992. &tpTokenPrivilege,
  1993. sizeof(TOKEN_PRIVILEGES),
  1994. NULL, // Ignore previous info
  1995. NULL)) // Ignore previous info
  1996. {
  1997. dwErr=GetLastError();
  1998. ErrorTrace(0, "AdjustTokenPrivileges %ld", dwErr);
  1999. goto done;
  2000. }
  2001. dwErr = ERROR_SUCCESS;
  2002. done:
  2003. if (hAccessToken != NULL)
  2004. {
  2005. _VERIFY(TRUE==CloseHandle(hAccessToken));
  2006. }
  2007. TraceFunctLeave();
  2008. return dwErr;
  2009. }
  2010. void RemoveReliabilityKey(WCHAR * pszSoftwareHive)
  2011. {
  2012. HKEY LocalKey = NULL;
  2013. DWORD dwStatus, disposition;
  2014. dwStatus = RegLoadKey( HKEY_LOCAL_MACHINE,
  2015. LOAD_KEY_NAME,
  2016. pszSoftwareHive);
  2017. if ( ERROR_SUCCESS == dwStatus )
  2018. {
  2019. /*
  2020. * Open the reliability key
  2021. */
  2022. dwStatus = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
  2023. LOAD_KEY_NAME TEXT("\\Microsoft\\Windows\\CurrentVersion\\Reliability"),
  2024. 0,
  2025. NULL,
  2026. REG_OPTION_BACKUP_RESTORE,
  2027. MAXIMUM_ALLOWED,
  2028. NULL,
  2029. &LocalKey,
  2030. &disposition );
  2031. if ( ERROR_SUCCESS == dwStatus )
  2032. {
  2033. RegDeleteValue( LocalKey, TEXT("LastAliveStamp") ) ;
  2034. RegCloseKey( LocalKey ) ;
  2035. }
  2036. RegFlushKey( HKEY_LOCAL_MACHINE );
  2037. RegUnLoadKey( HKEY_LOCAL_MACHINE, LOAD_KEY_NAME );
  2038. }
  2039. }
  2040. DWORD CopyHKLMHiveForRestore(WCHAR * pszSnapshotDir, // Directory where
  2041. // snapshot files are kept
  2042. const WCHAR * pszRegBackupFile)
  2043. // Registry backup file
  2044. {
  2045. TraceFunctEnter("CopyHKLMHiveForRestore");
  2046. DWORD dwErr, dwReturn = ERROR_INTERNAL_ERROR;
  2047. WCHAR szDataFile[MAX_PATH], szBackupFile[MAX_PATH];
  2048. if (IsRestoreCopy(pszRegBackupFile))
  2049. {
  2050. DebugTrace(0,"%S is already a backup file. Ignoring",pszRegBackupFile);
  2051. dwReturn = ERROR_SUCCESS;
  2052. goto cleanup;
  2053. }
  2054. /*
  2055. // if patch file, ignore
  2056. if (lstrcmpi(pszRegBackupFile + lstrlen(pszRegBackupFile) - lstrlen(s_cszPatchExtension), s_cszPatchExtension) != NULL)
  2057. {
  2058. DebugTrace(0, "%S is a patch file. Ignoring", pszRegBackupFile);
  2059. dwReturn = ERROR_SUCCESS;
  2060. goto cleanup;
  2061. }
  2062. */
  2063. // construct the path name of the datafile
  2064. wsprintf(szDataFile, L"%s\\%s", pszSnapshotDir, pszRegBackupFile);
  2065. // construct the path name of the backup file
  2066. wsprintf(szBackupFile, L"%s\\%s%s", pszSnapshotDir, pszRegBackupFile,
  2067. s_cszRegHiveCopySuffix);
  2068. dwErr = SnapshotCopyFile(szDataFile, szBackupFile);
  2069. if (ERROR_SUCCESS != dwErr)
  2070. {
  2071. dwReturn = dwErr;
  2072. goto cleanup;
  2073. }
  2074. dwReturn = ERROR_SUCCESS;
  2075. cleanup:
  2076. TraceFunctLeave();
  2077. return dwReturn;
  2078. }
  2079. DWORD RestoreHKLMHive(WCHAR * pszSnapshotDir, // Directory where
  2080. // snapshot files are kept
  2081. const WCHAR * pszRegBackupFile) // Registry backup file
  2082. {
  2083. TraceFunctEnter("RestoreHKLMHive");
  2084. DWORD dwErr, dwReturn = ERROR_INTERNAL_ERROR;
  2085. DWORD dwDisposition, dwHiveNameLength;
  2086. WCHAR szHiveName[MAX_PATH];
  2087. WCHAR szDataFile[MAX_PATH];
  2088. // first ignore anything with a . in it. This is because a
  2089. // valid HKLM hive file will not have a . in it.
  2090. if (wcschr(pszRegBackupFile, L'.'))
  2091. {
  2092. dwReturn = ERROR_SUCCESS;
  2093. goto cleanup;
  2094. }
  2095. // construct the Hive name
  2096. // 1. copy everything after the HKLM prefix into the buffer
  2097. lstrcpy(szHiveName,
  2098. pszRegBackupFile+ lstrlen(s_cszHKLMPrefix));
  2099. // 2. now NULL terminate where the RestoreCopySuffix starts
  2100. dwHiveNameLength = lstrlen(szHiveName) - lstrlen(s_cszRegHiveCopySuffix);
  2101. szHiveName[dwHiveNameLength] = L'\0';
  2102. // construct the path name of the datafile and the backup file
  2103. wsprintf(szDataFile, L"%s\\%s", pszSnapshotDir, pszRegBackupFile);
  2104. if (0==lstrcmpi(szHiveName, s_cszSoftwareHiveName))
  2105. {
  2106. // if this is the software key then the LastAliveStamp must
  2107. // be deleted
  2108. RemoveReliabilityKey(szDataFile);
  2109. }
  2110. dwErr = SetNewRegistry(HKEY_LOCAL_MACHINE, // handle to open key
  2111. szHiveName, // subkey name
  2112. szDataFile, // data file
  2113. NULL,
  2114. NULL);
  2115. if (ERROR_SUCCESS != dwErr)
  2116. {
  2117. ErrorTrace(0, "SetNewRegistry failed for %S, error %ld, file %S",
  2118. szHiveName, dwErr, pszRegBackupFile);
  2119. // now check to see if this is a well known HKLM hive. If not,
  2120. // ignore any errors in restoring this hive
  2121. if (FALSE==IsWellKnownHKLMHive(szHiveName))
  2122. {
  2123. dwReturn=ERROR_SUCCESS;
  2124. }
  2125. else
  2126. {
  2127. dwReturn = dwErr;
  2128. }
  2129. goto cleanup;
  2130. }
  2131. dwReturn = ERROR_SUCCESS;
  2132. cleanup:
  2133. TraceFunctLeave();
  2134. return dwReturn;
  2135. }
  2136. // the following loads the HKLM hive stored in the pszSnapshotDir
  2137. // in a temprary place.
  2138. DWORD LoadTempHKLM(IN WCHAR * pszSnapshotDir,
  2139. IN const WCHAR * pszHKLMHiveFile,
  2140. OUT HKEY * phKeyTempHKLM)
  2141. {
  2142. TraceFunctEnter("LoadTempHKLM");
  2143. DWORD dwErr, dwDisposition, i, dwResult=ERROR_INTERNAL_ERROR;
  2144. *phKeyTempHKLM = NULL;
  2145. dwErr = RegLoadKey( HKEY_LOCAL_MACHINE,// handle to open key
  2146. s_cszRestoreTempKey,// subkey name
  2147. pszHKLMHiveFile);// registry file name
  2148. if ( ERROR_SUCCESS != dwErr )
  2149. {
  2150. ErrorTrace(0, "Failed ::RegLoadKey('%S') ec=%d",
  2151. pszHKLMHiveFile, dwErr);
  2152. dwResult= dwErr;
  2153. goto cleanup;
  2154. }
  2155. // this is how to unload the above hive
  2156. // RegUnLoadKey( HKEY_LOCAL_MACHINE, s_cszRestoreTempKey);
  2157. dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,// handle to open key
  2158. s_cszRestoreTempKey,// subkey name
  2159. 0,// reserved
  2160. KEY_WRITE|KEY_READ,// security access mask
  2161. phKeyTempHKLM);// handle to open key
  2162. if (ERROR_SUCCESS != dwErr)
  2163. {
  2164. ErrorTrace(0,"Error %d in opening base key %S",
  2165. dwErr, s_cszRestoreTempKey);
  2166. _VERIFY(ERROR_SUCCESS == RegUnLoadKey( HKEY_LOCAL_MACHINE,
  2167. s_cszRestoreTempKey));
  2168. dwResult= dwErr;
  2169. goto cleanup;
  2170. }
  2171. dwResult = ERROR_SUCCESS;
  2172. cleanup:
  2173. TraceFunctLeave();
  2174. return dwResult;
  2175. }
  2176. DWORD
  2177. CSnapshot::RestoreRegistrySnapshot(WCHAR * pszSnapshotDir)
  2178. {
  2179. DWORD dwErr, dwReturn = ERROR_INTERNAL_ERROR;
  2180. HKEY hKeyTempHKLM=NULL;
  2181. WCHAR szHKLMHiveCopy[MAX_PATH], szHKLMHive[MAX_PATH];
  2182. WCHAR szHKLMPrefix[MAX_PATH];
  2183. CTokenPrivilege tp;
  2184. TraceFunctEnter("CSnapshot::RestoreRegistrySnapshot");
  2185. dwErr = tp.SetPrivilegeInAccessToken(SE_RESTORE_NAME);
  2186. if (ERROR_SUCCESS != dwErr)
  2187. {
  2188. ErrorTrace(0, "SetPrivilegeInAccessToken failed ec=%d", dwErr);
  2189. dwReturn = ERROR_PRIVILEGE_NOT_HELD;
  2190. goto cleanup;
  2191. }
  2192. // now create the path of the HKLM software hive.
  2193. // first construct the name of the file that stores the HKLM registry
  2194. // snapshot.
  2195. wsprintf(szHKLMHive,L"%s\\%s%s", pszSnapshotDir, s_cszHKLMFilePrefix,
  2196. s_cszSoftwareHiveName);
  2197. // to restore the user profiles, we need to first load the HKLM
  2198. // hive in a temporary place so that we can read the profile paths.
  2199. // copy this hive a temporary file
  2200. wsprintf(szHKLMHiveCopy, L"%s.backuphive", szHKLMHive);
  2201. DeleteFile(szHKLMHiveCopy); // delete it if it already exists
  2202. if (! CopyFile(szHKLMHive, szHKLMHiveCopy, FALSE))
  2203. {
  2204. dwErr = GetLastError();
  2205. ErrorTrace(0, "CopyFile failed. ec=%d", dwErr);
  2206. LogDSFileTrace(0,L"src= ", szHKLMHive);
  2207. LogDSFileTrace(0,L"dst= ", szHKLMHiveCopy);
  2208. if (ERROR_SUCCESS!= dwErr)
  2209. {
  2210. dwReturn = dwErr;
  2211. }
  2212. goto cleanup;
  2213. }
  2214. dwErr = LoadTempHKLM(pszSnapshotDir, szHKLMHiveCopy, &hKeyTempHKLM);
  2215. if (ERROR_SUCCESS != dwErr)
  2216. {
  2217. // could not load hKeyTempHKLM - fatal error
  2218. dwReturn = dwErr;
  2219. ErrorTrace(0, "LoadTempHKLM failed");
  2220. goto cleanup;
  2221. }
  2222. // need to copy back ntuser.dat for each user
  2223. dwErr = ProcessHKUsersKey(pszSnapshotDir,
  2224. hKeyTempHKLM,
  2225. TRUE); // need to do a restore - not a snapshot
  2226. if (ERROR_SUCCESS != dwErr)
  2227. {
  2228. ErrorTrace(0, "DoHKUsersSnapshot failed error %ld", dwErr);
  2229. dwReturn = dwErr;
  2230. goto cleanup;
  2231. }
  2232. // first construct the prefix of the files that store the HKLM registry
  2233. // snapshot.
  2234. wsprintf(szHKLMPrefix, L"%s\\%s*%s", pszSnapshotDir, s_cszHKLMFilePrefix,
  2235. s_cszRegHiveCopySuffix);
  2236. // need to use RegReplaceKey to restore each hive of the registry
  2237. dwErr = ProcessGivenFiles(pszSnapshotDir, RestoreHKLMHive,
  2238. szHKLMPrefix);
  2239. if (ERROR_SUCCESS != dwErr)
  2240. {
  2241. ErrorTrace(0, "ProcessGivenFiles failed error %ld", dwErr);
  2242. dwReturn = dwErr;
  2243. goto cleanup;
  2244. }
  2245. dwReturn = ERROR_SUCCESS;
  2246. cleanup:
  2247. // if the HKLM hive is loaded, unload it.
  2248. if (NULL != hKeyTempHKLM)
  2249. {
  2250. _VERIFY(ERROR_SUCCESS==RegCloseKey(hKeyTempHKLM));
  2251. _VERIFY(ERROR_SUCCESS == RegUnLoadKey( HKEY_LOCAL_MACHINE,
  2252. s_cszRestoreTempKey));
  2253. }
  2254. // delete the copy of HKLM software hive - note that this will
  2255. // fail if the copy file failed.
  2256. DeleteFile(szHKLMHiveCopy);
  2257. TraceFunctLeave();
  2258. return dwReturn;
  2259. }
  2260. DWORD
  2261. CSnapshot::RestoreCOMDbSnapshot(WCHAR * pszSnapShotDir)
  2262. {
  2263. // need to restore COM+ Db using RegDBRestore
  2264. TraceFunctEnter("CSnapshot::RestoreCOMDbSnapshot");
  2265. DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
  2266. HMODULE hModCOMDll=NULL;
  2267. HRESULT hr;
  2268. WCHAR szCOMDBFile[MAX_PATH];
  2269. if (NULL == m_pfnRegDbRestore)
  2270. {
  2271. dwErr = GetCOMplusRestoreFN();
  2272. if (ERROR_SUCCESS != dwErr)
  2273. {
  2274. dwReturn = dwErr;
  2275. goto cleanup;
  2276. }
  2277. }
  2278. // construct the path of the database backup file
  2279. CreateCOMDBSnapShotFileName(pszSnapShotDir, szCOMDBFile);
  2280. hr =m_pfnRegDbRestore( szCOMDBFile );
  2281. // call the function to backup the file
  2282. if ( FAILED(hr))
  2283. {
  2284. ErrorTrace(0, "Failed to restore COM DB. hr=0x%x", hr);
  2285. goto cleanup;
  2286. }
  2287. dwReturn = ERROR_SUCCESS;
  2288. cleanup:
  2289. TraceFunctLeave();
  2290. return dwReturn;
  2291. }
  2292. DWORD
  2293. CSnapshot::RestoreSnapshot(WCHAR * pszRestoreDir)
  2294. {
  2295. TraceFunctEnter("CSnapshot::RestoreSnapshot");
  2296. WCHAR szSnapShotDir[MAX_PATH];
  2297. DWORD dwErr;
  2298. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  2299. BOOL fCoInitialized = FALSE;
  2300. HKEY hKey = NULL;
  2301. struct {
  2302. DWORD FilelistFiles : 1;
  2303. DWORD COMDb : 1;
  2304. DWORD WMI : 1;
  2305. DWORD IIS : 1;
  2306. DWORD Registry : 1;
  2307. } ItemsCompleted = {0,0,0,0,0};
  2308. HRESULT hr;
  2309. // create the snapshot directory name from the restore directory
  2310. // name and create the actual directory.
  2311. lstrcpy(szSnapShotDir, pszRestoreDir);
  2312. lstrcat(szSnapShotDir, SNAPSHOT_DIR_NAME);
  2313. // does the directory exist ?
  2314. if (FALSE == DoesDirExist( szSnapShotDir)) // SD
  2315. {
  2316. ErrorTrace(0, "Snapshot directory does not exist");
  2317. goto cleanup;
  2318. }
  2319. // restore files listed in filelist.xml
  2320. dwErr = SnapshotRestoreFilelistFiles(szSnapShotDir, FALSE);
  2321. if (dwErr != ERROR_SUCCESS)
  2322. {
  2323. dwReturn = dwErr;
  2324. goto cleanup;
  2325. }
  2326. //
  2327. // mark completion
  2328. //
  2329. ItemsCompleted.FilelistFiles = 1;
  2330. // Restore COM snapshot
  2331. dwErr = RestoreCOMDbSnapshot(szSnapShotDir);
  2332. if (dwErr != ERROR_SUCCESS)
  2333. {
  2334. dwReturn = dwErr;
  2335. goto cleanup;
  2336. }
  2337. //
  2338. // mark completion
  2339. //
  2340. ItemsCompleted.COMDb = 1;
  2341. hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
  2342. if (hr == RPC_E_CHANGED_MODE)
  2343. {
  2344. //
  2345. // someone called it with other mode
  2346. //
  2347. hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );
  2348. }
  2349. if (FAILED(hr))
  2350. {
  2351. dwReturn = (DWORD) hr;
  2352. ErrorTrace(0, "! CoInitializeEx : %ld", dwReturn);
  2353. goto cleanup;
  2354. }
  2355. fCoInitialized = TRUE;
  2356. // restore perf counters
  2357. // restore WMI snapshot
  2358. dwErr = RestoreWMISnapshot(szSnapShotDir);
  2359. if (dwErr != ERROR_SUCCESS)
  2360. {
  2361. dwReturn = dwErr;
  2362. goto cleanup;
  2363. }
  2364. //
  2365. // mark completion
  2366. //
  2367. ItemsCompleted.WMI = 1;
  2368. // restore IIS snapshot
  2369. dwErr = RestoreIISSnapshot(szSnapShotDir);
  2370. if (dwErr != ERROR_SUCCESS)
  2371. {
  2372. dwReturn = dwErr;
  2373. goto cleanup;
  2374. }
  2375. //
  2376. // mark completion
  2377. //
  2378. ItemsCompleted.IIS = 1;
  2379. //
  2380. // support debug hook to force failure path
  2381. // this is checked before the registry restore
  2382. // because registry revert does not work
  2383. //
  2384. if ( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  2385. SRREG_PATH_SHELL,
  2386. 0,
  2387. KEY_READ,
  2388. &hKey) )
  2389. {
  2390. DWORD dwDebugTestUndo;
  2391. if (ERROR_SUCCESS == RegReadDWORD(hKey, SRREG_VAL_DEBUGTESTUNDO, &dwDebugTestUndo))
  2392. {
  2393. if (dwDebugTestUndo != 0)
  2394. {
  2395. DebugTrace(0, "*** Initiating UNDO for test purposes ***");
  2396. dwReturn = ERROR_INTERNAL_ERROR;
  2397. RegCloseKey(hKey);
  2398. goto cleanup;
  2399. }
  2400. }
  2401. RegCloseKey(hKey);
  2402. }
  2403. //
  2404. // now the registry snapshot is not atomic, so if we start it,
  2405. // we have should assume it made changes. so we mark it in advance
  2406. // such that it if fails, we will blast the safe registry over the current
  2407. // registry, effectively rolling back the partial changes the failed
  2408. // call made. this is a brute force, but simple, way to handle this error
  2409. // case, which we expect will never happen. InitRestoreSnapshot makes
  2410. // all of the proper checks to ensure this api will succeed when called.
  2411. //
  2412. //
  2413. // update: rollback of registry is not really working
  2414. // because RegReplaceKey fails on an already replaced hive
  2415. // so this might result in reverted user hives and unreverted software/system
  2416. // hives, which is pretty bad
  2417. // so disable this functionality
  2418. //
  2419. // ItemsCompleted.Registry = 1;
  2420. //
  2421. // Restore resgistry snapshot
  2422. //
  2423. dwErr = this->RestoreRegistrySnapshot(szSnapShotDir);
  2424. if (dwErr != ERROR_SUCCESS)
  2425. {
  2426. dwReturn = dwErr;
  2427. goto cleanup;
  2428. }
  2429. dwReturn = ERROR_SUCCESS;
  2430. cleanup:
  2431. //
  2432. // do we need to clean up any completed items due to a failed restore?
  2433. //
  2434. if (dwReturn != ERROR_SUCCESS)
  2435. {
  2436. CRestorePoint rp;
  2437. WCHAR szSafeDir[MAX_PATH];
  2438. WCHAR szSystemVolume[8];
  2439. dwErr = 0;
  2440. DebugTrace(0, "srrstr!Error in RestoreSnapshot\n");
  2441. //
  2442. // get the "current" restore point location, it has a snapshot
  2443. // of how things where prior to starting this restore
  2444. //
  2445. dwErr = GetCurrentRestorePoint(rp);
  2446. if (dwErr != ERROR_SUCCESS) {
  2447. DebugTrace(0, "srrstr!GetCurrentRestorePoint failed!\n");
  2448. goto end;
  2449. }
  2450. //
  2451. // make sure the "safe" snapshot is there for us to use
  2452. //
  2453. GetSystemDrive(szSystemVolume);
  2454. MakeRestorePath(szSafeDir, szSystemVolume, rp.GetDir());
  2455. if (ItemsCompleted.Registry) {
  2456. if (ERROR_SUCCESS != InitRestoreSnapshot(szSafeDir)) {
  2457. DebugTrace(0, "! InitRestoreSnapshot");
  2458. goto end;
  2459. }
  2460. }
  2461. lstrcat(szSafeDir, SNAPSHOT_DIR_NAME);
  2462. if (DoesDirExist(szSafeDir) == FALSE)
  2463. {
  2464. DebugTrace(0, "srrstr!Safe snapshot directory does not exist!\n");
  2465. goto end;
  2466. }
  2467. DebugTrace(0, "srrstr!Safe restore point %S\n", szSafeDir);
  2468. //
  2469. // roll them back in reverse order
  2470. //
  2471. if (ItemsCompleted.Registry) {
  2472. dwErr = RestoreRegistrySnapshot(szSafeDir);
  2473. // ignore any error's, we want to restore as much as we can
  2474. _ASSERT(dwErr == ERROR_SUCCESS);
  2475. DebugTrace(0, "srrstr!Restored registry\n");
  2476. }
  2477. if (ItemsCompleted.IIS) {
  2478. dwErr = RestoreIISSnapshot(szSafeDir);
  2479. // ignore any error's, we want to restore as much as we can
  2480. _ASSERT(dwErr == ERROR_SUCCESS);
  2481. DebugTrace(0, "srrstr!Restored IIS\n");
  2482. }
  2483. if (ItemsCompleted.WMI) {
  2484. dwErr = RestoreWMISnapshot(szSafeDir);
  2485. // ignore any error's, we want to restore as much as we can
  2486. _ASSERT(dwErr == ERROR_SUCCESS);
  2487. DebugTrace(0, "srrstr!Restored WMI\n");
  2488. }
  2489. if (ItemsCompleted.COMDb) {
  2490. dwErr = RestoreCOMDbSnapshot(szSafeDir);
  2491. // ignore any error's, we want to restore as much as we can
  2492. _ASSERT(dwErr == ERROR_SUCCESS);
  2493. DebugTrace(0, "srrstr!Restored COMDb\n");
  2494. }
  2495. if (ItemsCompleted.FilelistFiles) {
  2496. dwErr = SnapshotRestoreFilelistFiles(szSafeDir, FALSE);
  2497. // ignore any error's, we want to restore as much as we can
  2498. _ASSERT(dwErr == ERROR_SUCCESS);
  2499. DebugTrace(0, "srrstr!Restored FilelistFiles\n");
  2500. }
  2501. end:
  2502. //
  2503. // not much to do
  2504. //
  2505. ;
  2506. }
  2507. if (fCoInitialized)
  2508. CoUninitialize();
  2509. TraceFunctLeave();
  2510. return dwReturn;
  2511. }
  2512. // this returns the path of the system hive. The caller must pass
  2513. // in a buffer with lenght of this buffer in dwNumChars
  2514. DWORD
  2515. CSnapshot::GetSystemHivePath(WCHAR * pszRestoreDir,
  2516. WCHAR * pszHivePath,
  2517. DWORD dwNumChars)
  2518. {
  2519. // first construct the name of the file that stores the HKLM registry
  2520. // snapshot.
  2521. if (dwNumChars < MAX_PATH)
  2522. {
  2523. return ERROR_INSUFFICIENT_BUFFER;
  2524. }
  2525. wsprintf(pszHivePath,L"%s%s\\%s%s%s", pszRestoreDir, SNAPSHOT_DIR_NAME,
  2526. s_cszHKLMFilePrefix, s_cszSystemHiveName, s_cszRegHiveCopySuffix);
  2527. return ERROR_SUCCESS;
  2528. }
  2529. // this returns the path of the software hive. The caller must pass
  2530. // in a buffer with lenght of this buffer in dwNumChars
  2531. DWORD
  2532. CSnapshot::GetSoftwareHivePath(WCHAR * pszRestoreDir,
  2533. WCHAR * pszHivePath,
  2534. DWORD dwNumChars)
  2535. {
  2536. // first construct the name of the file that stores the HKLM registry
  2537. // snapshot.
  2538. if (dwNumChars < MAX_PATH)
  2539. {
  2540. return ERROR_INSUFFICIENT_BUFFER;
  2541. }
  2542. wsprintf(pszHivePath,L"%s%s\\%s%s%s", pszRestoreDir, SNAPSHOT_DIR_NAME,
  2543. s_cszHKLMFilePrefix, s_cszSoftwareHiveName,
  2544. s_cszRegHiveCopySuffix);
  2545. return ERROR_SUCCESS;
  2546. }
  2547. DWORD CSnapshot::GetSamHivePath (WCHAR * pszRestoreDir,
  2548. WCHAR * pszHivePath,
  2549. DWORD dwNumChars)
  2550. {
  2551. if (dwNumChars < MAX_PATH)
  2552. {
  2553. return ERROR_INSUFFICIENT_BUFFER;
  2554. }
  2555. wsprintf(pszHivePath,L"%s%s\\%s%s%s", pszRestoreDir, SNAPSHOT_DIR_NAME,
  2556. s_cszHKLMFilePrefix, s_cszSamHiveName,
  2557. s_cszRegHiveCopySuffix);
  2558. return ERROR_SUCCESS;
  2559. }
  2560. // this checks whether a specific HKLM registry hive is present in the
  2561. // snapshot directory
  2562. DWORD CheckHKLMFile(const WCHAR * pszSnapShotDir,
  2563. const WCHAR * pszHive)
  2564. {
  2565. BOOL dwReturn = ERROR_FILE_NOT_FOUND;
  2566. TraceFunctEnter("CheckHKLMFile");
  2567. WCHAR szHivePath[MAX_PATH];
  2568. // construct the name of the file
  2569. wsprintf(szHivePath,L"%s\\%s%s", pszSnapShotDir, s_cszHKLMFilePrefix,
  2570. pszHive);
  2571. if (FALSE == DoesFileExist(szHivePath))
  2572. {
  2573. LogDSFileTrace(0, L"Can't find", szHivePath);
  2574. goto cleanup;
  2575. }
  2576. dwReturn=ERROR_SUCCESS;
  2577. cleanup:
  2578. TraceFunctLeave();
  2579. return dwReturn;
  2580. }
  2581. // this checks whether all the files necessary to restore a snapshot
  2582. // are present in the snapshot directory
  2583. DWORD CheckforCriticalFiles(WCHAR * pszSnapShotDir)
  2584. {
  2585. TraceFunctEnter("CheckforCriticalFiles");
  2586. WCHAR szCOMDBFile[MAX_PATH];
  2587. DWORD dwRet=ERROR_FILE_NOT_FOUND;
  2588. dwRet=CheckHKLMFile(pszSnapShotDir,s_cszSoftwareHiveName);
  2589. VALIDATE_DWRET ("CheckHKLM file Software");
  2590. dwRet=CheckHKLMFile(pszSnapShotDir,s_cszSystemHiveName);
  2591. VALIDATE_DWRET ("CheckHKLM file System");
  2592. dwRet=CheckHKLMFile(pszSnapShotDir,s_cszSamHiveName);
  2593. VALIDATE_DWRET ("CheckHKLM file SAM");
  2594. dwRet=CheckHKLMFile(pszSnapShotDir,s_cszSecurityHiveName);
  2595. VALIDATE_DWRET ("CheckHKLM file Security");
  2596. // construct the path of the database backup file
  2597. CreateCOMDBSnapShotFileName(pszSnapShotDir, szCOMDBFile);
  2598. if (FALSE == DoesFileExist(szCOMDBFile))
  2599. {
  2600. LogDSFileTrace(0, L"Can't find", szCOMDBFile);
  2601. dwRet = ERROR_FILE_NOT_FOUND;
  2602. goto Exit;
  2603. }
  2604. dwRet=ERROR_SUCCESS;
  2605. Exit:
  2606. TraceFunctLeave();
  2607. return dwRet;
  2608. }
  2609. // This function must be called to Initialize a restore
  2610. // operation. This must be called before calling
  2611. // GetSystemHivePath GetSoftwareHivePath
  2612. DWORD
  2613. CSnapshot::InitRestoreSnapshot(WCHAR * pszRestoreDir)
  2614. {
  2615. TraceFunctEnter("InitRestoreSnapshot");
  2616. WCHAR szSnapshotDir[MAX_PATH];
  2617. WCHAR szHKLMPrefix[MAX_PATH];
  2618. // this copies all the HKLM registry hives to a temporary location
  2619. // since:
  2620. // 1. RegReplaceKey will move the file to another location, so
  2621. // we will lose the original registry hive.
  2622. // 2. We need to do this ahead of time becuase we do not want to
  2623. // run out of disk space in the middle of the restore.
  2624. // 3. Restore makes changes to the HKLM hives, we do not want
  2625. // restore to make these changes to the original registry hives.
  2626. DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
  2627. // create the snapshot directory name from the restore directory
  2628. // name and create the actual directory.
  2629. lstrcpy(szSnapshotDir, pszRestoreDir);
  2630. lstrcat(szSnapshotDir, SNAPSHOT_DIR_NAME);
  2631. // make sure no obsolete files are left from the previous restore
  2632. // could have happened if admin did not login since the last restore to this restore
  2633. // point
  2634. CleanupAfterRestore(pszRestoreDir);
  2635. dwErr = CheckforCriticalFiles(szSnapshotDir);
  2636. if (ERROR_SUCCESS != dwErr)
  2637. {
  2638. ErrorTrace(0,"CheckforCriticalFiles failed ec=%d",dwErr);
  2639. dwReturn = dwErr;
  2640. goto cleanup;
  2641. }
  2642. // first construct the prefix of the file that stores the HKLM registry
  2643. // snapshot.
  2644. wsprintf(szHKLMPrefix, L"%s\\%s*", szSnapshotDir, s_cszHKLMFilePrefix);
  2645. dwErr = ProcessGivenFiles(szSnapshotDir, CopyHKLMHiveForRestore,
  2646. szHKLMPrefix);
  2647. if (ERROR_SUCCESS != dwErr)
  2648. {
  2649. ErrorTrace(0, "copying hives failed error %ld", dwErr);
  2650. dwReturn = dwErr;
  2651. goto cleanup;
  2652. }
  2653. dwReturn = ERROR_SUCCESS;
  2654. cleanup:
  2655. TraceFunctLeave();
  2656. return dwReturn;
  2657. }
  2658. DWORD DeleteTempRestoreFile(WCHAR * pszSnapshotDir, // Directory where
  2659. // snapshot files are kept
  2660. const WCHAR * pszTempRestoreFile)
  2661. // Temp file created during restore
  2662. {
  2663. TraceFunctEnter("DeleteTempRestoreFile");
  2664. DWORD dwErr, dwReturn = ERROR_INTERNAL_ERROR;
  2665. WCHAR szDataFile[MAX_PATH];
  2666. // construct the path name of the file
  2667. wsprintf(szDataFile, L"%s\\%s", pszSnapshotDir, pszTempRestoreFile);
  2668. if (TRUE != DeleteFile(szDataFile))
  2669. {
  2670. dwErr = GetLastError();
  2671. if (ERROR_SUCCESS != dwErr)
  2672. {
  2673. dwReturn = dwErr;
  2674. }
  2675. ErrorTrace(0, "DeleteFile failed ec=%d", dwErr);
  2676. LogDSFileTrace(0,L"File was ", szDataFile);
  2677. // we will ignore a failure in deleting a file
  2678. //goto cleanup;
  2679. }
  2680. dwReturn = ERROR_SUCCESS;
  2681. //cleanup:
  2682. TraceFunctLeave();
  2683. return dwReturn;
  2684. }
  2685. DWORD DeleteAllFilesBySuffix(WCHAR * pszSnapshotDir,
  2686. const WCHAR * pszSuffix)
  2687. {
  2688. TraceFunctEnter("DeleteAllFilesBySuffix");
  2689. DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
  2690. WCHAR szFindFileData[MAX_PATH];
  2691. // first construct the prefix of the file that stores the HKLM registry
  2692. // snapshot.
  2693. wsprintf(szFindFileData, L"%s\\*%s", pszSnapshotDir, pszSuffix);
  2694. dwErr = ProcessGivenFiles(pszSnapshotDir, DeleteTempRestoreFile,
  2695. szFindFileData);
  2696. if (ERROR_SUCCESS != dwErr)
  2697. {
  2698. ErrorTrace(0, "Deleting files failed error %ld", dwErr);
  2699. dwReturn = dwErr;
  2700. goto cleanup;
  2701. }
  2702. dwReturn = ERROR_SUCCESS;
  2703. cleanup:
  2704. TraceFunctLeave();
  2705. return dwReturn;
  2706. }
  2707. // delete the reconstructed file corresponding to pszPatchFile
  2708. DWORD DeleteReconstructedTempFile(WCHAR * pszSnapshotDir,
  2709. const WCHAR * pszPatchFile)
  2710. {
  2711. TraceFunctEnter("DeleteReconstructedTempFile");
  2712. WCHAR szDataFile[MAX_PATH];
  2713. wsprintf(szDataFile, L"%s\\%s", pszSnapshotDir, pszPatchFile);
  2714. // remove the extension
  2715. szDataFile[lstrlen(szDataFile)-lstrlen(s_cszPatchExtension)] = L'\0';
  2716. if (TRUE != DeleteFile(szDataFile))
  2717. {
  2718. ErrorTrace(0, "! DeleteFile : %ld", GetLastError);
  2719. LogDSFileTrace(0, L"File was ", szDataFile);
  2720. }
  2721. TraceFunctLeave();
  2722. return ERROR_SUCCESS;
  2723. }
  2724. DWORD DeleteAllReconstructedFiles(WCHAR * pszSnapshotDir)
  2725. {
  2726. TraceFunctEnter("DeleteAllReconstructedFiles");
  2727. DWORD dwErr=ERROR_INTERNAL_ERROR;
  2728. WCHAR szFindFileData[MAX_PATH];
  2729. // first construct the prefix of the file that stores the HKLM registry
  2730. // snapshot.
  2731. wsprintf(szFindFileData, L"%s\\*%s", pszSnapshotDir, s_cszPatchExtension);
  2732. dwErr = ProcessGivenFiles(pszSnapshotDir, DeleteReconstructedTempFile,
  2733. szFindFileData);
  2734. if (ERROR_SUCCESS != dwErr)
  2735. {
  2736. ErrorTrace(0, "Deleting files failed error %ld", dwErr);
  2737. goto cleanup;
  2738. }
  2739. cleanup:
  2740. TraceFunctLeave();
  2741. return dwErr;
  2742. }
  2743. // this function is called after a restore operation. This deletes all
  2744. // the files that were created as part of the restore operation and
  2745. // are not needed now.
  2746. DWORD
  2747. CSnapshot::CleanupAfterRestore(WCHAR * pszRestoreDir)
  2748. {
  2749. WCHAR szSnapshotDir[MAX_PATH];
  2750. DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
  2751. // create the snapshot directory name from the restore directory
  2752. // name and create the actual directory.
  2753. lstrcpy(szSnapshotDir, pszRestoreDir);
  2754. lstrcat(szSnapshotDir, SNAPSHOT_DIR_NAME);
  2755. DeleteAllFilesBySuffix(szSnapshotDir, L".log");
  2756. DeleteAllFilesBySuffix(szSnapshotDir, s_cszRegHiveCopySuffix);
  2757. DeleteAllFilesBySuffix(szSnapshotDir, s_cszRegReplaceBackupSuffix );
  2758. //
  2759. // delete reconstructed files
  2760. //
  2761. DeleteAllReconstructedFiles(szSnapshotDir);
  2762. return ERROR_SUCCESS;
  2763. }
  2764. int MyExceptionFilter(int nExceptionCode)
  2765. {
  2766. TENTER("MyExceptionFilter");
  2767. trace(0, "Exception code=%d", nExceptionCode);
  2768. TLEAVE();
  2769. return EXCEPTION_EXECUTE_HANDLER;
  2770. }
  2771. //
  2772. // function to call any registered callbacks
  2773. // does not guarantee any order
  2774. //
  2775. DWORD
  2776. CallSnapshotCallbacks(
  2777. LPCWSTR pszEnumKey,
  2778. LPCWSTR pszSnapshotDir,
  2779. BOOL fSnapshot)
  2780. {
  2781. TraceFunctEnter("CallSnapshotCallbacks");
  2782. DWORD dwErr = ERROR_SUCCESS;
  2783. DWORD dwIndex = 0;
  2784. DWORD dwSize, dwDataSize;
  2785. WCHAR szDllPath[MAX_PATH], szDllName[MAX_PATH];
  2786. PSNAPSHOTCALLBACK pCallbackFn = NULL;
  2787. HKEY hKey = NULL;
  2788. HMODULE hDll = NULL;
  2789. //
  2790. // read SystemRestore\SnapshotCallbacks regkey
  2791. // enumerate all registered values
  2792. //
  2793. dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  2794. pszEnumKey,
  2795. 0,
  2796. KEY_READ,
  2797. &hKey);
  2798. if (dwErr != ERROR_SUCCESS) // assume key does not exist
  2799. {
  2800. dwErr = ERROR_SUCCESS;
  2801. DebugTrace(0, "No registered callbacks");
  2802. goto Err;
  2803. }
  2804. for (dwIndex = 0; TRUE; dwIndex ++)
  2805. {
  2806. dwSize = sizeof(szDllName)/sizeof(WCHAR); // this is in characters
  2807. dwDataSize = sizeof(szDllPath); // this is in bytes
  2808. dwErr = RegEnumValue(hKey, // handle to key to query
  2809. dwIndex, // index of value to query
  2810. szDllName, // value buffer
  2811. &dwSize, // size of value buffer
  2812. NULL, // reserved
  2813. NULL, // type buffer
  2814. (PBYTE) szDllPath, // data buffer
  2815. &dwDataSize); // size of data buffer
  2816. if (ERROR_SUCCESS != dwErr)
  2817. {
  2818. break;
  2819. }
  2820. if (0 == lstrcmp(szDllPath, L"") ||
  2821. 0 == lstrcmp(szDllPath, L" "))
  2822. continue;
  2823. //
  2824. // catch any exceptions that may happen in the callback dll
  2825. //
  2826. _try {
  2827. _try {
  2828. //
  2829. // load the registered library
  2830. // and call "CreateSnapshot" or "RestoreSnapshot" depending on the situation
  2831. //
  2832. hDll = LoadLibrary(szDllPath);
  2833. if (hDll != NULL)
  2834. {
  2835. pCallbackFn = (PSNAPSHOTCALLBACK) GetProcAddress(hDll, fSnapshot ? s_cszCreateSnapshotCallback :
  2836. s_cszRestoreSnapshotCallback);
  2837. if (pCallbackFn)
  2838. {
  2839. dwErr = (*pCallbackFn) (pszSnapshotDir);
  2840. if (dwErr != ERROR_SUCCESS)
  2841. {
  2842. ErrorTrace(0, "Dll: %S, Error:%ld - ignoring", szDllPath, dwErr);
  2843. dwErr = ERROR_SUCCESS;
  2844. }
  2845. }
  2846. else
  2847. {
  2848. ErrorTrace(0, "! GetProcAddress : %ld", GetLastError());
  2849. dwErr = GetLastError();
  2850. }
  2851. }
  2852. else
  2853. {
  2854. ErrorTrace(0, "! LoadLibrary on %S : %ld", szDllPath, GetLastError());
  2855. }
  2856. }
  2857. _finally {
  2858. if (hDll)
  2859. {
  2860. FreeLibrary(hDll);
  2861. hDll = NULL;
  2862. }
  2863. }
  2864. }
  2865. _except (MyExceptionFilter(GetExceptionCode())) {
  2866. //
  2867. // catch all exceptions right here
  2868. // we can't do much, just log it and keep going
  2869. //
  2870. ErrorTrace(0, "An exception occurred when loading and executing %S", szDllPath);
  2871. ErrorTrace(0, "Handled exception - continuing");
  2872. }
  2873. }
  2874. if (dwErr == ERROR_NO_MORE_ITEMS)
  2875. dwErr = ERROR_SUCCESS;
  2876. Err:
  2877. if (hKey)
  2878. RegCloseKey(hKey);
  2879. TraceFunctLeave();
  2880. return dwErr;
  2881. }