Leaked source code of windows server 2003
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.

1208 lines
30 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999
  5. //
  6. // File: restore.cpp
  7. //
  8. // Contents: Cert Server client database restore APIs
  9. //
  10. //---------------------------------------------------------------------------
  11. #include <pch.cpp>
  12. #pragma hdrstop
  13. #include "certsrvd.h"
  14. #include "csdisp.h"
  15. #include "certadmp.h"
  16. #define __dwFILE__ __dwFILE_CERTADM_RESTORE_CPP__
  17. extern WCHAR g_wszRestoreAnnotation[];
  18. //+--------------------------------------------------------------------------
  19. // CertSrvServerControl -- send a control command to the cert server.
  20. //
  21. // Parameters:
  22. // [in] pwszConfig - name or config string of the server to control
  23. // [in] dwControlFlags - control command and flags
  24. // [out] pcbOut - pointer to receive the size of command output data
  25. // [out] ppbOut - pointer to receive command output data. Use the
  26. // CertSrvBackupFree() API to free the buffer.
  27. //
  28. // Returns:
  29. // S_OK if the call executed successfully;
  30. // Failure code otherwise.
  31. //+--------------------------------------------------------------------------
  32. HRESULT
  33. CERTBCLI_API
  34. CertSrvServerControlW(
  35. IN WCHAR const *pwszConfig,
  36. IN DWORD dwControlFlags,
  37. OPTIONAL OUT DWORD *pcbOut,
  38. OPTIONAL OUT BYTE **ppbOut)
  39. {
  40. HRESULT hr;
  41. ICertAdminD2 *pICertAdminD = NULL;
  42. DWORD dwServerVersion;
  43. WCHAR const *pwszAuthority;
  44. CERTTRANSBLOB ctbOut = { 0, NULL };
  45. if (NULL != pcbOut)
  46. {
  47. *pcbOut = 0;
  48. }
  49. if (NULL != ppbOut)
  50. {
  51. *ppbOut = NULL;
  52. }
  53. if (NULL == pwszConfig)
  54. {
  55. hr = E_POINTER;
  56. _JumpError(hr, error, "NULL parm");
  57. }
  58. hr = S_OK;
  59. __try
  60. {
  61. hr = OpenAdminServer(
  62. pwszConfig,
  63. &pwszAuthority,
  64. &dwServerVersion,
  65. &pICertAdminD);
  66. _LeaveIfError(hr, "OpenAdminServer");
  67. hr = pICertAdminD->ServerControl(
  68. pwszAuthority,
  69. dwControlFlags,
  70. &ctbOut);
  71. _LeaveIfError(hr, "ServerControl");
  72. if (NULL != ctbOut.pb && NULL != ppbOut)
  73. {
  74. *ppbOut = (BYTE *) LocalAlloc(LMEM_FIXED, ctbOut.cb);
  75. if (NULL == *ppbOut)
  76. {
  77. hr = E_OUTOFMEMORY;
  78. _LeaveError(hr, "LocalAlloc");
  79. }
  80. CopyMemory(*ppbOut, ctbOut.pb, ctbOut.cb);
  81. if (NULL != pcbOut)
  82. {
  83. *pcbOut = ctbOut.cb;
  84. }
  85. }
  86. }
  87. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  88. {
  89. }
  90. error:
  91. if (NULL != ctbOut.pb)
  92. {
  93. CoTaskMemFree(ctbOut.pb);
  94. }
  95. if (NULL != pICertAdminD)
  96. {
  97. CloseAdminServer(&pICertAdminD);
  98. }
  99. return(hr);
  100. }
  101. //+--------------------------------------------------------------------------
  102. // CertSrvRestorePrepare -- indicate beginning of a restore session.
  103. //
  104. // Parameters:
  105. // [in] pwszConfig - name of the server into which the restore
  106. // operation is going to be performed.
  107. // [in] dwRestoreFlags - Or'ed combination of RESTORE_TYPE_* flags; 0 if
  108. // no special flags are to be specified
  109. // [out] phbc - pointer to receive the backup context handle which is to
  110. // be passed to the subsequent restore APIs
  111. //
  112. // Returns:
  113. // S_OK if the call executed successfully;
  114. // Failure code otherwise.
  115. //---------------------------------------------------------------------------
  116. HRESULT
  117. CERTBCLI_API
  118. CertSrvRestorePrepareW(
  119. IN WCHAR const *pwszConfig,
  120. IN ULONG dwRestoreFlags,
  121. OUT HCSBC *phbc)
  122. {
  123. HRESULT hr;
  124. CSBACKUPCONTEXT *pcsbc = NULL;
  125. if (NULL == pwszConfig || NULL == phbc)
  126. {
  127. hr = E_POINTER;
  128. _JumpError(hr, error, "NULL parm");
  129. }
  130. *phbc = NULL;
  131. if (~CSRESTORE_TYPE_FULL & dwRestoreFlags)
  132. {
  133. hr = E_INVALIDARG;
  134. _JumpError(hr, error, "dwRestoreFlags");
  135. }
  136. hr = AllocateContext(pwszConfig, &pcsbc);
  137. _JumpIfError(hr, error, "AllocateContext");
  138. pcsbc->RestoreFlags = dwRestoreFlags;
  139. *phbc = (HCSBC) pcsbc;
  140. pcsbc = NULL;
  141. error:
  142. if (NULL != pcsbc)
  143. {
  144. ReleaseContext(pcsbc);
  145. }
  146. return(hr);
  147. }
  148. //+--------------------------------------------------------------------------
  149. // CertSrvRestoreGetDatabaseLocations -- called both at backup time as well as at
  150. // restore time to get data base locations for different types of files.
  151. //
  152. // Parameters:
  153. // [in] hbc - backup context handle which would have been obtained
  154. // through CertSrvBackupPrepare in the backup case and through
  155. // CertSrvRestorePrepare in the restore case.
  156. // [out] ppwszzFileList - pointer that will receive the pointer
  157. // to the list of database locations; allocated memory should be
  158. // freed using CertSrvBackupFree() API by the caller when it is no
  159. // longer needed; locations are returned in an array of null
  160. // terminated names and and the list is terminated by two L'\0's.
  161. // The first character of each name is the BFT character that
  162. // indicates the type of the file and the rest of the name tells
  163. // gives the path into which that particular type of file should
  164. // be restored.
  165. // [out] pcbList - will receive the number of bytes returned
  166. //
  167. // Returns:
  168. // S_OK if the call executed successfully;
  169. // Failure code otherwise.
  170. //
  171. // Note:
  172. // This API returns only the fully qualified path of the databases, not the
  173. // name of the databases.
  174. //---------------------------------------------------------------------------
  175. HRESULT
  176. CERTBCLI_API
  177. CertSrvRestoreGetDatabaseLocationsW(
  178. IN HCSBC hbc,
  179. OUT WCHAR **ppwszzFileList,
  180. OUT DWORD *pcbList)
  181. {
  182. HRESULT hr;
  183. if (NULL == hbc)
  184. {
  185. hr = E_HANDLE;
  186. _JumpError(hr, error, "NULL handle");
  187. }
  188. if (NULL == ppwszzFileList || NULL == pcbList)
  189. {
  190. hr = E_POINTER;
  191. _JumpError(hr, error, "NULL parm");
  192. }
  193. hr = S_OK;
  194. __try
  195. {
  196. hr = BackupRestoreGetFileList(
  197. FLT_RESTOREDBLOCATIONS,
  198. hbc,
  199. ppwszzFileList,
  200. pcbList);
  201. _LeaveIfError(hr, "BackupRestoreGetFileList");
  202. }
  203. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  204. {
  205. }
  206. error:
  207. return(hr);
  208. }
  209. HRESULT
  210. CleanupOldLogs(
  211. OPTIONAL IN WCHAR const *pwszConfig,
  212. OPTIONAL IN HKEY hkey,
  213. OPTIONAL IN WCHAR const *pwszLogPath,
  214. IN ULONG genLow,
  215. IN ULONG genHigh)
  216. {
  217. HRESULT hr;
  218. DWORD cb;
  219. DWORD dwType;
  220. HANDLE hFind = INVALID_HANDLE_VALUE;
  221. WCHAR *pwsz;
  222. WCHAR *pwszLogPathUNC = NULL;
  223. WCHAR *pwszLogPathLocal = NULL;
  224. WCHAR *pwszLogPathWild = NULL;
  225. WIN32_FIND_DATA wfd;
  226. WCHAR wszServer[MAX_PATH];
  227. WCHAR wszLogFileName[2 * MAX_PATH]; // UNC logfile name
  228. WCHAR *pwszFileName; // filename (edb0006A.log)
  229. if (genHigh < genLow)
  230. {
  231. hr = E_INVALIDARG;
  232. _JumpError(hr, error, "bad parm");
  233. }
  234. wszServer[0] = L'\0';
  235. if (NULL != pwszConfig)
  236. {
  237. // Allow UNC-style config strings: \\server\CAName
  238. while (L'\\' == *pwszConfig)
  239. {
  240. pwszConfig++;
  241. }
  242. wcscpy(wszServer, pwszConfig);
  243. pwsz = wcschr(wszServer, L'\\');
  244. if (NULL != pwsz)
  245. {
  246. *pwsz = L'\0';
  247. }
  248. }
  249. // If the Log Path wasn't passed in, fetch it from the server's registry
  250. if (NULL == pwszLogPath)
  251. {
  252. if (NULL == hkey)
  253. {
  254. hr = E_POINTER;
  255. _JumpError(hr, error, "NULL parm");
  256. }
  257. cb = sizeof(wszLogFileName);
  258. hr = RegQueryValueEx(
  259. hkey,
  260. wszREGDBLOGDIRECTORY,
  261. 0,
  262. &dwType,
  263. (BYTE *) wszLogFileName,
  264. &cb);
  265. _JumpIfError(hr, error, "RegQueryValueEx");
  266. // Assume remote access -- convert to UNC path
  267. hr = myConvertLocalPathToUNC(
  268. wszServer,
  269. wszLogFileName,
  270. &pwszLogPathUNC);
  271. _JumpIfError(hr, error, "myConvertLocalPathToUNC");
  272. pwszLogPath = pwszLogPathUNC;
  273. }
  274. // If local machine -- convert UNC path to Local Path
  275. if (NULL == pwszConfig)
  276. {
  277. hr = myConvertUNCPathToLocal(pwszLogPath, &pwszLogPathLocal);
  278. _JumpIfError(hr, error, "myConvertUNCPathToLocal");
  279. pwszLogPath = pwszLogPathLocal;
  280. }
  281. // copy the LogPath -- it's of the form "\\server\c$\winnt\ntlog" or
  282. // "c:\winnt\ntlog", possibly with a trailing backslash
  283. //
  284. // make two copies of the logpath - one to pass a wildcard string for
  285. // searching and other to create filenames with full path for the logfiles
  286. hr = myBuildPathAndExt(
  287. pwszLogPath,
  288. L"edb*.log",
  289. NULL, // pwszExt
  290. &pwszLogPathWild);
  291. _JumpIfError(hr, error, "myBuildPathAndExt");
  292. // make pwszFileName point past the last backslash in wszLogFileName
  293. wcscpy(wszLogFileName, pwszLogPathWild);
  294. pwszFileName = wcsrchr(wszLogFileName, L'\\');
  295. CSASSERT(NULL != pwszFileName);
  296. pwszFileName++;
  297. hFind = FindFirstFile(pwszLogPathWild, &wfd);
  298. if (INVALID_HANDLE_VALUE != hFind)
  299. {
  300. do
  301. {
  302. // wfd.cFileName points to the name of edb*.log file found
  303. ULONG ulLogNo = wcstoul(wfd.cFileName + 3, NULL, 16);
  304. if (ulLogNo < genLow || ulLogNo > genHigh)
  305. {
  306. // This is an old logfile which was not copied down by ntbackup
  307. // -- clean it up. First append the filename to the logpath
  308. // (Note: pwszFileName already points past the end of the final
  309. // backslash in logpath). Then delete the file by passing in
  310. // the full path.
  311. wcscpy(pwszFileName, wfd.cFileName);
  312. //printf("Deleting: %ws\n", wszLogFileName);
  313. if (!DeleteFile(wszLogFileName))
  314. {
  315. // Unable to delete the old logfile; not cleaning up will
  316. // cause problems later. Return failure code.
  317. hr = myHLastError();
  318. _JumpError(hr, error, "DeleteFile");
  319. }
  320. }
  321. } while (FindNextFile(hFind, &wfd));
  322. hr = myHLastError();
  323. if (HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES) != hr)
  324. {
  325. // we came out of the loop for some unexpected error -- return the
  326. // error code.
  327. _JumpError(hr, error, "FindNextFile");
  328. }
  329. }
  330. hr = S_OK;
  331. error:
  332. if (NULL != pwszLogPathUNC)
  333. {
  334. LocalFree(pwszLogPathUNC);
  335. }
  336. if (NULL != pwszLogPathLocal)
  337. {
  338. LocalFree(pwszLogPathLocal);
  339. }
  340. if (NULL != pwszLogPathWild)
  341. {
  342. LocalFree(pwszLogPathWild);
  343. }
  344. if (INVALID_HANDLE_VALUE != hFind)
  345. {
  346. FindClose(hFind);
  347. }
  348. return(hr);
  349. }
  350. //+--------------------------------------------------------------------------
  351. // CertSrvRestoreRegister -- register a restore operation. It will interlock all
  352. // subsequent restore operations, and will prevent the restore target from
  353. // starting until the call to CertSrvRestoreRegisterComplete is made.
  354. //
  355. // Parameters:
  356. // [in] hbc - backup context handle for the restore session.
  357. // [in] pwszCheckPointFilePath - path to restore the check point files
  358. // [in] pwszLogPath - path where the log files are restored
  359. // [in] rgrstmap - restore map
  360. // [in] crstmap - tells if there is a new restore map
  361. // [in] pwszBackupLogPath - path where the backup logs are located
  362. // [in] genLow - Lowest log# that was restored in this restore session
  363. // [in] genHigh - Highest log# that was restored in this restore session
  364. //
  365. // Returns:
  366. // S_OK if the call executed successfully;
  367. // Failure code otherwise.
  368. //---------------------------------------------------------------------------
  369. HRESULT
  370. CERTBCLI_API
  371. CertSrvRestoreRegisterW(
  372. OPTIONAL IN HCSBC hbc,
  373. OPTIONAL IN WCHAR const *pwszCheckPointFilePath,
  374. OPTIONAL IN WCHAR const *pwszLogPath,
  375. OPTIONAL IN CSEDB_RSTMAPW rgrstmap[],
  376. IN LONG crstmap,
  377. OPTIONAL IN WCHAR const *pwszBackupLogPath,
  378. IN ULONG genLow,
  379. IN ULONG genHigh)
  380. {
  381. HRESULT hr;
  382. WCHAR const *pwszConfig = NULL;
  383. HKEY hkey = NULL;
  384. HKEY hkeyRestore = NULL;
  385. WCHAR *pwszPath = NULL;
  386. DWORD cwcRstMap;
  387. WCHAR *pwszRstMap = NULL;
  388. WCHAR *pwsz;
  389. LONG i;
  390. DWORD dwDisposition;
  391. DWORD dwType;
  392. DWORD cbGen;
  393. ULONG genCurrent;
  394. BOOLEAN fDatabaseRecovered = FALSE;
  395. #if DBG_CERTSRV
  396. if (NULL != getenv("certsrv_CertSrvRestoreRegisterThroughFile"))
  397. {
  398. hr = E_ACCESSDENIED;
  399. _JumpError(hr, error, "force CertSrvRestoreRegisterThroughFile");
  400. }
  401. #endif
  402. if (0 != crstmap && NULL == rgrstmap)
  403. {
  404. hr = E_POINTER;
  405. _JumpError(hr, error, "NULL parm");
  406. }
  407. if (NULL != hbc)
  408. {
  409. CSBACKUPCONTEXT *pcsbc = (CSBACKUPCONTEXT *) hbc;
  410. pwszConfig = pcsbc->pwszConfig;
  411. }
  412. hr = myRegOpenRelativeKey(
  413. pwszConfig,
  414. L"",
  415. RORKF_CREATESUBKEYS,
  416. &pwszPath,
  417. NULL, // ppwszName
  418. &hkey);
  419. // If the registry key doesn't exist, and we're restoring the local
  420. // machine, create it now. The rest of the registry will be restored
  421. // prior to starting the cert server to recover the cert server database.
  422. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  423. {
  424. BOOL fLocal = TRUE;
  425. if (NULL != pwszConfig)
  426. {
  427. hr = myIsConfigLocal(pwszConfig, NULL, &fLocal);
  428. _JumpIfErrorStr(hr, error, "myIsConfigLocal", pwszConfig);
  429. }
  430. if (fLocal)
  431. {
  432. hr = RegCreateKeyEx(
  433. HKEY_LOCAL_MACHINE,
  434. wszREGKEYCONFIGPATH,
  435. 0, // Reserved
  436. NULL, // lpClass
  437. 0, // dwOptions
  438. KEY_ALL_ACCESS,
  439. NULL,
  440. &hkey,
  441. &dwDisposition);
  442. _JumpIfError(hr, error, "RegCreateKeyEx");
  443. }
  444. else
  445. {
  446. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  447. }
  448. }
  449. _JumpIfErrorStr(hr, error, "myRegOpenRelativeKey", pwszConfig);
  450. hr = RegCreateKeyEx(
  451. hkey,
  452. wszREGKEYRESTOREINPROGRESS,
  453. 0, // Reserved
  454. NULL, // lpClass
  455. 0, // dwOptions
  456. KEY_ALL_ACCESS,
  457. NULL,
  458. &hkeyRestore,
  459. &dwDisposition);
  460. _JumpIfError(hr, error, "RegCreateKeyEx");
  461. // Seed the restore-in-progress in the registry.
  462. hr = CERTSRV_E_SERVER_SUSPENDED;
  463. hr = RegSetValueEx(
  464. hkeyRestore,
  465. wszREGRESTORESTATUS,
  466. 0,
  467. REG_DWORD,
  468. (BYTE *) &hr,
  469. sizeof(DWORD));
  470. _JumpIfError(hr, error, "RegSetValueEx");
  471. // We've now interlocked other restore operations from coming in from other
  472. // machines.
  473. if (0 != crstmap)
  474. {
  475. // Full backup:
  476. //
  477. // The restore map should only be set on a full backup. If there's
  478. // already a restore map size (or restore map), then this full backup
  479. // is overriding a previously incomplete full backup.
  480. // Save away the size of the restore map.
  481. hr = RegSetValueEx(
  482. hkeyRestore,
  483. wszREGRESTOREMAPCOUNT,
  484. 0,
  485. REG_DWORD,
  486. (BYTE *) &crstmap,
  487. sizeof(DWORD));
  488. // We now need to convert the restore map into one that we can put
  489. // into the registry. First figure out how big it will be.
  490. cwcRstMap = 1;
  491. for (i = 0 ; i < crstmap ; i++)
  492. {
  493. cwcRstMap +=
  494. myLocalPathwcslen(rgrstmap[i].pwszDatabaseName) + 1 +
  495. myLocalPathwcslen(rgrstmap[i].pwszNewDatabaseName) + 1;
  496. }
  497. pwszRstMap = (WCHAR *) LocalAlloc(
  498. LMEM_FIXED,
  499. cwcRstMap * sizeof(WCHAR));
  500. if (NULL == pwszRstMap)
  501. {
  502. hr = E_OUTOFMEMORY;
  503. _JumpError(hr, error, "LocalAlloc");
  504. }
  505. pwsz = pwszRstMap;
  506. for (i = 0 ; i < crstmap ; i++)
  507. {
  508. myLocalPathwcscpy(pwsz, rgrstmap[i].pwszDatabaseName);
  509. pwsz += wcslen(pwsz) + 1;
  510. myLocalPathwcscpy(pwsz, rgrstmap[i].pwszNewDatabaseName);
  511. pwsz += wcslen(pwsz) + 1;
  512. }
  513. *pwsz++ = L'\0';
  514. hr = RegSetValueEx(
  515. hkeyRestore,
  516. wszREGRESTOREMAP,
  517. 0,
  518. REG_MULTI_SZ,
  519. (BYTE *) pwszRstMap,
  520. SAFE_SUBTRACT_POINTERS(
  521. (BYTE *) pwsz,
  522. (BYTE *) pwszRstMap));
  523. }
  524. else
  525. {
  526. // Incremental backup:
  527. //
  528. // Fail if no restore map exists -- Insist that a full backup be in
  529. // progress...
  530. cbGen = sizeof(genCurrent);
  531. hr = RegQueryValueEx(
  532. hkeyRestore,
  533. wszREGRESTOREMAPCOUNT,
  534. 0,
  535. &dwType,
  536. (BYTE *) &genCurrent,
  537. &cbGen);
  538. _JumpIfError(hr, error, "RegQueryValueEx");
  539. // Expand genLow and genHigh to include previously registered log files
  540. cbGen = sizeof(genCurrent);
  541. hr = RegQueryValueEx(
  542. hkeyRestore,
  543. wszREGLOWLOGNUMBER,
  544. 0,
  545. &dwType,
  546. (BYTE *) &genCurrent,
  547. &cbGen);
  548. if (S_OK == hr &&
  549. REG_DWORD == dwType &&
  550. sizeof(genCurrent) == cbGen &&
  551. genLow > genCurrent)
  552. {
  553. genLow = genCurrent;
  554. }
  555. cbGen = sizeof(genCurrent);
  556. hr = RegQueryValueEx(
  557. hkeyRestore,
  558. wszREGHIGHLOGNUMBER,
  559. 0,
  560. &dwType,
  561. (BYTE *) &genCurrent,
  562. &cbGen);
  563. if (S_OK == hr &&
  564. REG_DWORD == dwType &&
  565. sizeof(genCurrent) == cbGen &&
  566. genHigh < genCurrent)
  567. {
  568. genHigh = genCurrent;
  569. }
  570. }
  571. hr = RegSetValueEx(
  572. hkeyRestore,
  573. wszREGLOWLOGNUMBER,
  574. 0,
  575. REG_DWORD,
  576. (BYTE *) &genLow,
  577. sizeof(DWORD));
  578. _JumpIfError(hr, error, "RegSetValueEx");
  579. hr = RegSetValueEx(
  580. hkeyRestore,
  581. wszREGHIGHLOGNUMBER,
  582. 0,
  583. REG_DWORD,
  584. (BYTE *) &genHigh,
  585. sizeof(DWORD));
  586. _JumpIfError(hr, error, "RegSetValueEx");
  587. if (NULL != pwszBackupLogPath)
  588. {
  589. hr = mySetRegistryLocalPathString(
  590. hkeyRestore,
  591. wszREGBACKUPLOGDIRECTORY,
  592. pwszBackupLogPath);
  593. _JumpIfError(hr, error, "mySetRegistryLocalPathString");
  594. }
  595. if (NULL != pwszCheckPointFilePath)
  596. {
  597. hr = mySetRegistryLocalPathString(
  598. hkeyRestore,
  599. wszREGCHECKPOINTFILE,
  600. pwszCheckPointFilePath);
  601. _JumpIfError(hr, error, "mySetRegistryLocalPathString");
  602. }
  603. if (NULL != pwszLogPath)
  604. {
  605. hr = mySetRegistryLocalPathString(
  606. hkeyRestore,
  607. wszREGLOGPATH,
  608. pwszLogPath);
  609. _JumpIfError(hr, error, "mySetRegistryLocalPathString");
  610. }
  611. // Reset the "database recovered" bit.
  612. hr = RegSetValueEx(
  613. hkeyRestore,
  614. wszREGDATABASERECOVERED,
  615. 0,
  616. REG_BINARY,
  617. (BYTE *) &fDatabaseRecovered,
  618. sizeof(BOOLEAN));
  619. _JumpIfError(hr, error, "RegSetValueEx");
  620. // We have successfully registered the restore, now cleanup any
  621. // pre-existing logfiles in the logdir to avoid JetExternalRestore using
  622. // logfiles that are not specified by the low and high log numbers.
  623. hr = CleanupOldLogs(pwszConfig, hkey, pwszLogPath, genLow, genHigh);
  624. _JumpIfError(hr, error, "CleanupOldLogs");
  625. error:
  626. if (NULL != pwszRstMap)
  627. {
  628. LocalFree(pwszRstMap);
  629. }
  630. if (NULL != hkeyRestore)
  631. {
  632. RegCloseKey(hkeyRestore);
  633. }
  634. if (NULL != hkey)
  635. {
  636. RegCloseKey(hkey);
  637. }
  638. if (NULL != pwszPath)
  639. {
  640. LocalFree(pwszPath);
  641. }
  642. hr = myHError(hr);
  643. return hr;
  644. }
  645. //+--------------------------------------------------------------------------
  646. // CertSrvRestoreRegisterComplete -- indicate that a previously registered restore
  647. // is complete.
  648. //
  649. // Parameters:
  650. // [in] hbc - backup context handle
  651. // [in] hrRestoreState - success code if the restore was successful
  652. //
  653. // Returns:
  654. // S_OK if the call executed successfully;
  655. // Failure code otherwise.
  656. //---------------------------------------------------------------------------
  657. HRESULT
  658. CERTBCLI_API
  659. CertSrvRestoreRegisterComplete(
  660. OPTIONAL IN HCSBC hbc,
  661. IN HRESULT hrRestore)
  662. {
  663. HRESULT hr;
  664. WCHAR const *pwszConfig = NULL;
  665. HKEY hkey = NULL;
  666. HKEY hkeyRestore = NULL;
  667. WCHAR *pwszPath = NULL;
  668. DWORD dwDisposition;
  669. if (NULL != hbc)
  670. {
  671. CSBACKUPCONTEXT *pcsbc = (CSBACKUPCONTEXT *) hbc;
  672. pwszConfig = pcsbc->pwszConfig;
  673. }
  674. if (S_OK != hrRestore && SUCCEEDED(hrRestore))
  675. {
  676. hr = E_INVALIDARG;
  677. _JumpError(hr, error, "hrRestore");
  678. }
  679. hr = myRegOpenRelativeKey(
  680. pwszConfig,
  681. L"",
  682. RORKF_CREATESUBKEYS,
  683. &pwszPath,
  684. NULL, // ppwszName
  685. &hkey);
  686. _JumpIfErrorStr(hr, error, "myRegOpenRelativeKey", pwszConfig);
  687. hr = RegCreateKeyEx(
  688. hkey,
  689. wszREGKEYRESTOREINPROGRESS,
  690. 0, // Reserved
  691. NULL, // lpClass
  692. 0, // dwOptions
  693. KEY_ALL_ACCESS,
  694. NULL,
  695. &hkeyRestore,
  696. &dwDisposition);
  697. _JumpIfError(hr, error, "RegCreateKeyEx");
  698. // If the restore status is not S_OK, then set the status to the error.
  699. // If the restore status is success, then clear the restore-in-progress
  700. // indicator.
  701. if (S_OK != hrRestore)
  702. {
  703. hr = RegSetValueEx(
  704. hkeyRestore,
  705. wszREGRESTORESTATUS,
  706. 0,
  707. REG_DWORD,
  708. (BYTE *) &hrRestore,
  709. sizeof(DWORD));
  710. _JumpIfError(hr, error, "RegSetValueEx");
  711. }
  712. else
  713. {
  714. hr = RegDeleteValue(hkeyRestore, wszREGRESTORESTATUS);
  715. _JumpIfError(hr, error, "RegDeleteValue");
  716. }
  717. error:
  718. if (NULL != hkeyRestore)
  719. {
  720. RegCloseKey(hkeyRestore);
  721. }
  722. if (NULL != hkey)
  723. {
  724. RegCloseKey(hkey);
  725. }
  726. if (NULL != pwszPath)
  727. {
  728. LocalFree(pwszPath);
  729. }
  730. return(hr);
  731. }
  732. //+--------------------------------------------------------------------------
  733. // CertSrvRestoreEnd -- end a restore session
  734. //
  735. // Parameters:
  736. // [in] hbc - backup context handle
  737. //
  738. // Returns:
  739. // S_OK if the call executed successfully;
  740. // Failure code otherwise.
  741. //---------------------------------------------------------------------------
  742. HRESULT
  743. CERTBCLI_API
  744. CertSrvRestoreEnd(
  745. IN HCSBC hbc)
  746. {
  747. HRESULT hr;
  748. if (NULL == hbc)
  749. {
  750. hr = E_HANDLE;
  751. _JumpError(hr, error, "NULL handle");
  752. }
  753. hr = S_OK;
  754. __try
  755. {
  756. ReleaseContext((CSBACKUPCONTEXT *) hbc);
  757. }
  758. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  759. {
  760. }
  761. error:
  762. return(hr);
  763. }
  764. HRESULT
  765. rsGetRestoreDataDWORD(
  766. IN LPCWSTR pwszRestoreFile,
  767. IN LPCWSTR pwszName,
  768. OUT DWORD *pdwData)
  769. {
  770. WCHAR buffer[cwcDWORDSPRINTF];
  771. GetPrivateProfileString(
  772. wszRESTORE_SECTION,
  773. pwszName,
  774. L"",
  775. buffer,
  776. ARRAYSIZE(buffer),
  777. pwszRestoreFile);
  778. if (0 == wcscmp(buffer, L""))
  779. {
  780. return(S_FALSE);
  781. }
  782. *pdwData = _wtoi(buffer);
  783. return(S_OK);
  784. }
  785. HRESULT
  786. CERTBCLI_API
  787. CertSrvRestoreRegisterThroughFile(
  788. IN HCSBC hbc,
  789. OPTIONAL IN WCHAR const *pwszCheckPointFilePath,
  790. OPTIONAL IN WCHAR const *pwszLogPath,
  791. OPTIONAL IN CSEDB_RSTMAPW rgrstmap[],
  792. IN LONG crstmap,
  793. OPTIONAL IN WCHAR const *pwszBackupLogPath,
  794. IN ULONG genLow,
  795. IN ULONG genHigh)
  796. {
  797. HRESULT hr = S_OK;
  798. WCHAR const *pwszConfig = NULL;
  799. LONG i;
  800. DWORD dwType;
  801. ULONG genCurrent;
  802. BOOLEAN fDatabaseRecovered = FALSE;
  803. WCHAR wszLogPath[MAX_PATH+1];
  804. WCHAR wszFormat[256]; // must fit MAXDWORD
  805. WCHAR wszKeyName[256]; // must fit RestoreMapN
  806. LPWSTR pwszLogPathUNC = NULL;
  807. HKEY hkey = NULL;
  808. LPWSTR pwszPath = NULL;
  809. LPWSTR pwszRestoreFile = NULL;
  810. LPWSTR pwszServer = NULL;
  811. LPWSTR pwszAuthority = NULL;
  812. if (!hbc ||
  813. (0 != crstmap && NULL == rgrstmap))
  814. {
  815. hr = E_POINTER;
  816. _JumpError(hr, error, "NULL parm");
  817. }
  818. pwszConfig = ((CSBACKUPCONTEXT *) hbc)->pwszConfig;
  819. if (NULL == pwszLogPath)
  820. {
  821. DWORD cb;
  822. hr = myRegOpenRelativeKey(
  823. pwszConfig,
  824. L"",
  825. 0,
  826. &pwszPath,
  827. NULL, // ppwszName
  828. &hkey);
  829. _JumpIfError(hr, error, "RegQueryValueEx");
  830. cb = sizeof(wszLogPath);
  831. hr = RegQueryValueEx(
  832. hkey,
  833. wszREGDBLOGDIRECTORY,
  834. 0,
  835. &dwType,
  836. (BYTE *) wszLogPath,
  837. &cb);
  838. _JumpIfError(hr, error, "RegQueryValueEx");
  839. pwszLogPath = wszLogPath;
  840. }
  841. if (L'\\' != pwszLogPath[0] || L'\\' != pwszLogPath[1])
  842. {
  843. // local path - convert to UNC for the INI file
  844. if (NULL != pwszConfig) // if remote access
  845. {
  846. hr = mySplitConfigString(pwszConfig, &pwszServer, &pwszAuthority);
  847. _JumpIfError(hr, error, "mySplitConfigString");
  848. }
  849. else // else local machine
  850. {
  851. hr = myGetMachineDnsName(&pwszServer);
  852. _JumpIfError(hr, error, "myGetMachineDnsName");
  853. }
  854. hr = myConvertLocalPathToUNC(pwszServer, pwszLogPath, &pwszLogPathUNC);
  855. _JumpIfError(hr, error, "myConvertLocalPathToUNC");
  856. }
  857. pwszRestoreFile = (LPWSTR) LocalAlloc(
  858. LMEM_FIXED,
  859. sizeof(WCHAR) * (
  860. wcslen(pwszLogPath) +
  861. wcslen(wszRESTORE_FILENAME) +
  862. 2));
  863. _JumpIfAllocFailed(pwszRestoreFile, error);
  864. wcscpy(pwszRestoreFile, pwszLogPath);
  865. wcscat(pwszRestoreFile, L"\\");
  866. wcscat(pwszRestoreFile, wszRESTORE_FILENAME);
  867. wsprintf(wszFormat, L"%d", CERTSRV_E_SERVER_SUSPENDED);
  868. if (!WritePrivateProfileString(
  869. wszRESTORE_SECTION,
  870. wszREGRESTORESTATUS,
  871. wszFormat,
  872. pwszRestoreFile))
  873. {
  874. hr = myHLastError();
  875. _JumpError(hr, error, "WritePrivateProfileString");
  876. }
  877. if (0 != crstmap)
  878. {
  879. // Full backup:
  880. //
  881. // The restore map should only be set on a full backup. If there's
  882. // already a restore map size (or restore map), then this full backup
  883. // is overriding a previously incomplete full backup.
  884. wsprintf(wszFormat, L"%d", crstmap);
  885. if (!WritePrivateProfileString(
  886. wszRESTORE_SECTION,
  887. wszREGRESTOREMAPCOUNT,
  888. wszFormat,
  889. pwszRestoreFile))
  890. {
  891. hr = myHLastError();
  892. _JumpError(hr, error, "WritePrivateProfileString");
  893. }
  894. for (i = 0 ; i < crstmap ; i++)
  895. {
  896. WCHAR wszPath[MAX_PATH];
  897. wsprintf(wszKeyName, L"%ws%d", wszREGRESTOREMAP, i);
  898. myLocalPathwcscpy(wszPath, rgrstmap[i].pwszDatabaseName);
  899. if (!WritePrivateProfileString(
  900. wszRESTORE_SECTION,
  901. wszKeyName,
  902. wszPath,
  903. pwszRestoreFile))
  904. {
  905. hr = myHLastError();
  906. _JumpError(hr, error, "WritePrivateProfileInt");
  907. }
  908. wsprintf(
  909. wszKeyName,
  910. L"%ws%ws%d",
  911. wszREGRESTOREMAP,
  912. wszRESTORE_NEWLOGSUFFIX,
  913. i);
  914. myLocalPathwcscpy(wszPath, rgrstmap[i].pwszNewDatabaseName);
  915. if (!WritePrivateProfileString(
  916. wszRESTORE_SECTION,
  917. wszKeyName,
  918. wszPath,
  919. pwszRestoreFile))
  920. {
  921. hr = myHLastError();
  922. _JumpError(hr, error, "WritePrivateProfileInt");
  923. }
  924. }
  925. }
  926. else
  927. {
  928. // Incremental backup:
  929. //
  930. // Fail if no restore map exists -- Insist that a full backup be in
  931. // progress...
  932. hr = rsGetRestoreDataDWORD(
  933. pwszRestoreFile,
  934. wszREGRESTOREMAPCOUNT,
  935. &genCurrent);
  936. if (S_FALSE == hr)
  937. {
  938. hr = E_ABORT; // mandatory
  939. }
  940. _JumpIfError(
  941. hr,
  942. error,
  943. "restore ini file invalid, wszREGRESTOREMAPCOUNT not found");
  944. // Expand genLow and genHigh to include previously registered log files
  945. hr = rsGetRestoreDataDWORD(
  946. pwszRestoreFile,
  947. wszREGLOWLOGNUMBER,
  948. &genCurrent);
  949. if (S_OK == hr && genLow > genCurrent)
  950. {
  951. genLow = genCurrent;
  952. }
  953. hr = rsGetRestoreDataDWORD(
  954. pwszRestoreFile,
  955. wszREGHIGHLOGNUMBER,
  956. &genCurrent);
  957. if (S_OK == hr && genHigh < genCurrent)
  958. {
  959. genHigh = genCurrent;
  960. }
  961. }
  962. // dword wszREGLOWLOGNUMBER=genLow
  963. wsprintf(wszFormat, L"%d", genLow);
  964. if (!WritePrivateProfileString(
  965. wszRESTORE_SECTION,
  966. wszREGLOWLOGNUMBER,
  967. wszFormat,
  968. pwszRestoreFile))
  969. {
  970. hr = myHLastError();
  971. _JumpError(hr, error, "WritePrivateProfileString");
  972. }
  973. // dword wszREGHIGHLOGNUMBER=genHigh
  974. wsprintf(wszFormat, L"%d", genHigh);
  975. if (!WritePrivateProfileString(
  976. wszRESTORE_SECTION,
  977. wszREGHIGHLOGNUMBER,
  978. wszFormat,
  979. pwszRestoreFile))
  980. {
  981. hr = myHLastError();
  982. _JumpError(hr, error, "WritePrivateProfileString");
  983. }
  984. // string wszREGBACKUPLOGDIRECTORY=pwszBackupLogPath
  985. if (!WritePrivateProfileString(
  986. wszRESTORE_SECTION,
  987. wszREGBACKUPLOGDIRECTORY,
  988. pwszBackupLogPath,
  989. pwszRestoreFile))
  990. {
  991. hr = myHLastError();
  992. _JumpError(hr, error, "WritePrivateProfileString");
  993. }
  994. // string wszREGCHECKPOINTFILE=pwszCheckPointFilePath
  995. if (!WritePrivateProfileString(
  996. wszRESTORE_SECTION,
  997. wszREGCHECKPOINTFILE,
  998. pwszCheckPointFilePath,
  999. pwszRestoreFile))
  1000. {
  1001. hr = myHLastError();
  1002. _JumpError(hr, error, "WritePrivateProfileString");
  1003. }
  1004. // string wszREGLOGPATH=pwszLogPath -- always write a UNC path
  1005. if (!WritePrivateProfileString(
  1006. wszRESTORE_SECTION,
  1007. wszREGLOGPATH,
  1008. NULL != pwszLogPathUNC? pwszLogPathUNC : pwszLogPath,
  1009. pwszRestoreFile))
  1010. {
  1011. hr = myHLastError();
  1012. _JumpError(hr, error, "WritePrivateProfileString");
  1013. }
  1014. // dword wszREGDATABASERECOVERED=fDatabaseRecovered
  1015. wsprintf(wszFormat, L"%d", fDatabaseRecovered);
  1016. if (!WritePrivateProfileString(
  1017. wszRESTORE_SECTION,
  1018. wszREGDATABASERECOVERED,
  1019. wszFormat,
  1020. pwszRestoreFile))
  1021. {
  1022. hr = myHLastError();
  1023. _JumpError(hr, error, "WritePrivateProfileString");
  1024. }
  1025. // We have successfully registered the restore, now cleanup any
  1026. // pre-existing logfiles in the logdir to avoid JetExternalRestore using
  1027. // logfiles that are not specified by the low and high log numbers.
  1028. CSASSERT(NULL != pwszLogPath);
  1029. hr = CleanupOldLogs(pwszConfig, hkey, pwszLogPath, genLow, genHigh);
  1030. _JumpIfError(hr, error, "CleanupOldLogs");
  1031. // delete restore status error
  1032. if (!WritePrivateProfileString(
  1033. wszRESTORE_SECTION,
  1034. wszREGRESTORESTATUS,
  1035. NULL,
  1036. pwszRestoreFile))
  1037. {
  1038. hr = myHLastError();
  1039. _JumpError(hr, error, "WritePrivateProfileString");
  1040. }
  1041. error:
  1042. if (S_OK != hr && NULL != pwszRestoreFile)
  1043. {
  1044. // in case of failure, try to delete restore file
  1045. if (!DeleteFile(pwszRestoreFile))
  1046. {
  1047. _PrintIfError(myHLastError(), "DeleteFile");
  1048. }
  1049. }
  1050. LOCAL_FREE(pwszPath);
  1051. LOCAL_FREE(pwszLogPathUNC);
  1052. LOCAL_FREE(pwszRestoreFile);
  1053. LOCAL_FREE(pwszServer);
  1054. LOCAL_FREE(pwszAuthority);
  1055. if (NULL != hkey)
  1056. {
  1057. RegCloseKey(hkey);
  1058. }
  1059. return(hr);
  1060. }