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.

1240 lines
31 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999
  5. //
  6. // File: db3.cpp
  7. //
  8. // Contents: Cert Server Database interface implementation
  9. //
  10. // History: 13-June-97 larrys created
  11. //
  12. //---------------------------------------------------------------------------
  13. #include <pch.cpp>
  14. #pragma hdrstop
  15. #include <stdio.h>
  16. #include "csprop.h"
  17. #define __dwFILE__ __dwFILE_CERTSRV_DB3_CPP__
  18. ICertDB *g_pCertDB = NULL;
  19. BOOL g_fDBRecovered = FALSE;
  20. WCHAR g_wszDatabase[MAX_PATH];
  21. WCHAR g_wszLogDir[MAX_PATH];
  22. WCHAR g_wszSystemDir[MAX_PATH];
  23. const WCHAR g_wszCertSrvDotExe[] = L"certsrv.exe";
  24. const int MAXDWORD_STRLEN = 11;
  25. HRESULT
  26. dbCheckRecoveryState(
  27. IN HKEY hkeyConfig,
  28. IN DWORD cSession,
  29. IN DWORD DBFlags,
  30. IN WCHAR const *pwszEventSource,
  31. IN WCHAR const *pwszLogDir,
  32. IN WCHAR const *pwszSystemDir,
  33. IN WCHAR const *pwszTempDir);
  34. typedef struct _REGDBDIR
  35. {
  36. WCHAR const *pwszRegName;
  37. BOOL fMustExist;
  38. WCHAR *pwszBuf;
  39. } REGDBDIR;
  40. HRESULT dbGetRestoreDataDWORD(
  41. LPCWSTR pwszRestoreFile,
  42. LPCWSTR pwszName,
  43. DWORD* pdwData)
  44. {
  45. WCHAR buffer[MAXDWORD_STRLEN]; // large enough to fit MAXDWORD decimal (4294967295)
  46. GetPrivateProfileString(
  47. wszRESTORE_SECTION,
  48. pwszName,
  49. L"",
  50. buffer,
  51. ARRAYSIZE(buffer),
  52. pwszRestoreFile);
  53. if(0==wcscmp(buffer, L""))
  54. {
  55. return S_FALSE;
  56. }
  57. *pdwData = _wtoi(buffer);
  58. return S_OK;
  59. }
  60. HRESULT dbGetRestoreDataLPWSZ(
  61. LPCWSTR pwszRestoreFile,
  62. LPCWSTR pwszName,
  63. LPWSTR* ppwszData)
  64. {
  65. HRESULT hr = S_OK;
  66. WCHAR buffer[MAX_PATH+1];
  67. GetPrivateProfileString(
  68. wszRESTORE_SECTION,
  69. pwszName,
  70. L"",
  71. buffer,
  72. ARRAYSIZE(buffer),
  73. pwszRestoreFile);
  74. if(0==wcscmp(buffer, L""))
  75. {
  76. return S_FALSE;
  77. }
  78. *ppwszData = (LPWSTR)LocalAlloc(LMEM_FIXED,
  79. sizeof(WCHAR)*(wcslen(buffer)+1));
  80. _JumpIfAllocFailed(*ppwszData, error);
  81. wcscpy(*ppwszData, buffer);
  82. error:
  83. return hr;
  84. }
  85. HRESULT dbGetRestoreDataMULTISZ(
  86. LPCWSTR pwszRestoreFile,
  87. LPCWSTR pwszName,
  88. LPWSTR *ppwszData,
  89. DWORD *pcbData)
  90. {
  91. HRESULT hr = S_OK;
  92. WCHAR buffer[MAX_PATH+1];
  93. int cData;
  94. LPWSTR pwszFullName = NULL;
  95. DWORD cbData = 0;
  96. LPWSTR pwszData = NULL;
  97. WCHAR *pwszCrt = NULL; // no free
  98. pwszFullName = (LPWSTR)LocalAlloc(LMEM_FIXED,
  99. sizeof(WCHAR)*
  100. (wcslen(pwszName)+
  101. wcslen(wszRESTORE_NEWLOGSUFFIX)+
  102. MAXDWORD_STRLEN+1));
  103. _JumpIfAllocFailed(pwszFullName, error);
  104. wcscpy(pwszFullName, L"");
  105. for(cbData=0, cData = 0;; cData++)
  106. {
  107. wsprintf(pwszFullName, L"%s%d", pwszName, cData);
  108. GetPrivateProfileString(
  109. wszRESTORE_SECTION,
  110. pwszFullName,
  111. L"",
  112. buffer,
  113. ARRAYSIZE(buffer),
  114. pwszRestoreFile);
  115. if(0==wcscmp(buffer, L""))
  116. {
  117. if(0==cData)
  118. {
  119. hr = S_FALSE;
  120. _JumpErrorStr(hr, error, "no restore data", pwszRestoreFile);
  121. }
  122. else
  123. {
  124. break;
  125. }
  126. }
  127. cbData += wcslen(buffer)+1;
  128. wsprintf(pwszFullName, L"%s%s%d", pwszName, wszRESTORE_NEWLOGSUFFIX,
  129. cData);
  130. GetPrivateProfileString(
  131. wszRESTORE_SECTION,
  132. pwszFullName,
  133. L"",
  134. buffer,
  135. ARRAYSIZE(buffer),
  136. pwszRestoreFile);
  137. if(0==wcscmp(buffer, L""))
  138. {
  139. hr = ERROR_INVALID_DATA;
  140. _JumpErrorStr(hr, error,
  141. "restore file contains inconsistent data", pwszRestoreFile);
  142. }
  143. cbData += wcslen(buffer)+1;
  144. }
  145. cbData++; // trailing zero
  146. cbData *= sizeof(WCHAR);
  147. pwszData = (LPWSTR)LocalAlloc(LMEM_FIXED, cbData);
  148. _JumpIfAllocFailed(pwszData, error);
  149. for(pwszCrt=pwszData, cData = 0;; cData++)
  150. {
  151. wsprintf(pwszFullName, L"%s%d", pwszName, cData);
  152. GetPrivateProfileString(
  153. wszRESTORE_SECTION,
  154. pwszFullName,
  155. L"",
  156. buffer,
  157. ARRAYSIZE(buffer),
  158. pwszRestoreFile);
  159. if(0==wcscmp(buffer, L""))
  160. {
  161. break;
  162. }
  163. wcscpy(pwszCrt, buffer);
  164. pwszCrt += wcslen(buffer)+1;
  165. wsprintf(pwszFullName, L"%s%s%d", pwszName, wszRESTORE_NEWLOGSUFFIX,
  166. cData);
  167. GetPrivateProfileString(
  168. wszRESTORE_SECTION,
  169. pwszFullName,
  170. L"",
  171. buffer,
  172. ARRAYSIZE(buffer),
  173. pwszRestoreFile);
  174. wcscpy(pwszCrt, buffer);
  175. pwszCrt += wcslen(buffer)+1;
  176. }
  177. *pwszCrt = L'\0';
  178. *ppwszData = pwszData;
  179. *pcbData = cbData;
  180. error:
  181. LOCAL_FREE(pwszFullName);
  182. if(S_OK!=hr)
  183. {
  184. LOCAL_FREE(pwszData);
  185. }
  186. return hr;
  187. }
  188. HRESULT dbRestoreRecoveryStateFromFile(LPCWSTR pwszLogDir)
  189. {
  190. HRESULT hr = S_OK;
  191. LPWSTR pwszRestoreFile = NULL;
  192. WCHAR buffer[256];
  193. DWORD dwRestoreMapCount,
  194. dwRegLowLogNumber,
  195. dwRegHighLogNumber,
  196. dwDatabaseRecovered;
  197. LPWSTR pwszRestoreMap = NULL;
  198. DWORD cbRestoreMap = 0;
  199. LPWSTR pwszPath = NULL;
  200. HKEY hkey = NULL;
  201. DWORD dwDisposition;
  202. HKEY hkeyRestore = NULL;
  203. BOOL fDatabaseRecovered;
  204. LPWSTR pwszBackupLogDir = NULL;
  205. LPWSTR pwszCheckpointFile = NULL;
  206. LPWSTR pwszLogPath = NULL;
  207. CSASSERT(pwszLogDir);
  208. pwszRestoreFile = (LPWSTR)LocalAlloc(LMEM_FIXED,
  209. sizeof(WCHAR)*(wcslen(pwszLogDir)+wcslen(wszRESTORE_FILENAME)+2));
  210. _JumpIfAllocFailed(pwszRestoreFile, error);
  211. wcscpy(pwszRestoreFile, pwszLogDir);
  212. wcscat(pwszRestoreFile, L"\\");
  213. wcscat(pwszRestoreFile, wszRESTORE_FILENAME);
  214. // is there a restore state file?
  215. if(-1 != GetFileAttributes(pwszRestoreFile))
  216. {
  217. // check first if a restore is in progress
  218. GetPrivateProfileString(
  219. wszRESTORE_SECTION,
  220. wszREGRESTORESTATUS,
  221. L"",
  222. buffer,
  223. ARRAYSIZE(buffer),
  224. pwszRestoreFile);
  225. if(wcscmp(buffer, L""))
  226. {
  227. // restore in progress, bail
  228. hr = _wtoi(buffer);
  229. _JumpError(hr, error, "A restore is in progress");
  230. }
  231. hr = myRegOpenRelativeKey(
  232. NULL,
  233. L"",
  234. RORKF_CREATESUBKEYS,
  235. &pwszPath,
  236. NULL, // ppwszName
  237. &hkey);
  238. _JumpIfError(hr, error, "myRegOpenRelativeKey");
  239. hr = RegCreateKeyEx(
  240. hkey,
  241. wszREGKEYRESTOREINPROGRESS,
  242. 0, // Reserved
  243. NULL, // lpClass
  244. 0, // dwOptions
  245. KEY_ALL_ACCESS,
  246. NULL,
  247. &hkeyRestore,
  248. &dwDisposition);
  249. _JumpIfErrorStr(hr, error, "RegCreateKeyEx", wszREGKEYRESTOREINPROGRESS);
  250. hr = dbGetRestoreDataDWORD(
  251. pwszRestoreFile,
  252. wszREGRESTOREMAPCOUNT,
  253. &dwRestoreMapCount);
  254. if(S_FALSE==hr)
  255. {
  256. // mandatory
  257. hr = E_ABORT;
  258. }
  259. _JumpIfError(hr, error,
  260. "restore ini file invalid, wszREGRESTOREMAPCOUNT not found" );
  261. hr = dbGetRestoreDataDWORD(
  262. pwszRestoreFile,
  263. wszREGLOWLOGNUMBER,
  264. &dwRegLowLogNumber);
  265. if(S_FALSE==hr)
  266. {
  267. // mandatory
  268. hr = E_ABORT;
  269. }
  270. _JumpIfError(hr, error,
  271. "restore ini file invalid, wszREGLOWLOGNUMBER not found" );
  272. hr = dbGetRestoreDataDWORD(
  273. pwszRestoreFile,
  274. wszREGHIGHLOGNUMBER,
  275. &dwRegHighLogNumber);
  276. if(S_FALSE==hr)
  277. {
  278. // mandatory
  279. hr = E_ABORT;
  280. }
  281. _JumpIfError(hr, error,
  282. "restore ini file invalid, wszREGHIGHLOGNUMBER not found" );
  283. hr = dbGetRestoreDataDWORD(
  284. pwszRestoreFile,
  285. wszREGDATABASERECOVERED,
  286. &dwDatabaseRecovered);
  287. if(S_FALSE==hr)
  288. {
  289. // mandatory
  290. hr = E_ABORT;
  291. }
  292. _JumpIfError(hr, error,
  293. "restore ini file invalid, wszREGDATABASERECOVERED not found" );
  294. fDatabaseRecovered = dwDatabaseRecovered?TRUE:FALSE;
  295. hr = dbGetRestoreDataLPWSZ(
  296. pwszRestoreFile,
  297. wszREGBACKUPLOGDIRECTORY,
  298. &pwszBackupLogDir);
  299. if(S_FALSE==hr)
  300. {
  301. // optional
  302. hr = S_OK;
  303. }
  304. _JumpIfErrorStr(hr, error, "dbGetRestoreDataLPWSZ", wszREGBACKUPLOGDIRECTORY );
  305. hr = dbGetRestoreDataLPWSZ(
  306. pwszRestoreFile,
  307. wszREGCHECKPOINTFILE,
  308. &pwszCheckpointFile);
  309. if(S_FALSE==hr)
  310. {
  311. // optional
  312. hr = S_OK;
  313. }
  314. _JumpIfErrorStr(hr, error, "dbGetRestoreDataLPWSZ", wszREGCHECKPOINTFILE );
  315. hr = dbGetRestoreDataLPWSZ(
  316. pwszRestoreFile,
  317. wszREGLOGPATH,
  318. &pwszLogPath);
  319. if(S_FALSE==hr)
  320. {
  321. // optional
  322. hr = S_OK;
  323. }
  324. _JumpIfErrorStr(hr, error, "dbGetRestoreDataLPWSZ", wszREGLOGPATH );
  325. hr = dbGetRestoreDataMULTISZ(
  326. pwszRestoreFile,
  327. wszREGRESTOREMAP,
  328. &pwszRestoreMap,
  329. &cbRestoreMap);
  330. if(S_FALSE==hr)
  331. {
  332. // optional
  333. hr = S_OK;
  334. }
  335. _JumpIfErrorStr(hr, error, "dbGetRestoreDataDWORD", L"wszRESTOREMAP");
  336. hr = RegSetValueEx(
  337. hkeyRestore,
  338. wszREGRESTOREMAPCOUNT,
  339. 0,
  340. REG_DWORD,
  341. (BYTE *) &dwRestoreMapCount,
  342. sizeof(DWORD));
  343. _JumpIfErrorStr(hr, error, "RegSetValueEx", wszREGRESTOREMAPCOUNT);
  344. hr = RegSetValueEx(
  345. hkeyRestore,
  346. wszREGLOWLOGNUMBER,
  347. 0,
  348. REG_DWORD,
  349. (BYTE *) &dwRegLowLogNumber,
  350. sizeof(DWORD));
  351. _JumpIfErrorStr(hr, error, "RegSetValueEx", wszREGLOWLOGNUMBER);
  352. hr = RegSetValueEx(
  353. hkeyRestore,
  354. wszREGHIGHLOGNUMBER,
  355. 0,
  356. REG_DWORD,
  357. (BYTE *) &dwRegHighLogNumber,
  358. sizeof(DWORD));
  359. _JumpIfErrorStr(hr, error, "RegSetValueEx", wszREGHIGHLOGNUMBER);
  360. hr = RegSetValueEx(
  361. hkeyRestore,
  362. wszREGDATABASERECOVERED,
  363. 0,
  364. REG_BINARY,
  365. (BYTE *) &fDatabaseRecovered,
  366. sizeof(BOOLEAN));
  367. _JumpIfError(hr, error, "RegSetValueEx");
  368. if(pwszBackupLogDir)
  369. {
  370. hr = mySetRegistryLocalPathString(
  371. hkeyRestore,
  372. wszREGBACKUPLOGDIRECTORY,
  373. pwszBackupLogDir);
  374. _JumpIfErrorStr(hr, error, "mySetRegistryLocalPathString",
  375. wszREGBACKUPLOGDIRECTORY);
  376. }
  377. if(pwszCheckpointFile)
  378. {
  379. hr = mySetRegistryLocalPathString(
  380. hkeyRestore,
  381. wszREGCHECKPOINTFILE,
  382. pwszCheckpointFile);
  383. _JumpIfErrorStr(hr, error, "mySetRegistryLocalPathString",
  384. wszREGCHECKPOINTFILE);
  385. }
  386. if(pwszLogPath)
  387. {
  388. hr = mySetRegistryLocalPathString(
  389. hkeyRestore,
  390. wszREGLOGPATH,
  391. pwszLogPath);
  392. _JumpIfErrorStr(hr, error, "mySetRegistryLocalPathString",
  393. wszREGCHECKPOINTFILE);
  394. }
  395. if(pwszRestoreMap)
  396. {
  397. hr = RegSetValueEx(
  398. hkeyRestore,
  399. wszREGRESTOREMAP,
  400. 0,
  401. REG_MULTI_SZ,
  402. (BYTE *) pwszRestoreMap,
  403. cbRestoreMap);
  404. _JumpIfErrorStr(hr, error, "RegSetValueEx", wszREGRESTOREMAP);
  405. }
  406. if(!DeleteFile(pwszRestoreFile))
  407. {
  408. _PrintError(myHLastError(), "DeleteFile restore file");
  409. }
  410. }
  411. else
  412. {
  413. hr = myHLastError();
  414. // no restore state file OK
  415. if(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
  416. hr = S_OK;
  417. _JumpIfErrorStr(hr, error, "GetFileAttributes", pwszRestoreFile);
  418. }
  419. error:
  420. LOCAL_FREE(pwszRestoreFile);
  421. LOCAL_FREE(pwszRestoreMap);
  422. LOCAL_FREE(pwszPath);
  423. LOCAL_FREE(pwszBackupLogDir);
  424. LOCAL_FREE(pwszCheckpointFile);
  425. LOCAL_FREE(pwszLogPath);
  426. if(hkey)
  427. {
  428. RegCloseKey(hkey);
  429. }
  430. if(hkeyRestore)
  431. {
  432. RegCloseKey(hkeyRestore);
  433. }
  434. return hr;
  435. }
  436. //+--------------------------------------------------------------------------
  437. // DB file storage locations:
  438. //
  439. // wszREGDBDIRECTORY:
  440. // Your Name.EDB from csregstr.h: wszDBFILENAMEEXT .edb
  441. //
  442. // wszREGDBLOGDIRECTORY:
  443. // EDB.log from csregstr.h: wszDBBASENAMEPARM edb
  444. // EDB00001.log from csregstr.h: wszDBBASENAMEPARM edb
  445. // EDB00002.log from csregstr.h: wszDBBASENAMEPARM edb
  446. // res1.log
  447. // res2.log
  448. //
  449. // wszREGDBSYSDIRECTORY:
  450. // EDB.chk from csregstr.h: wszDBBASENAMEPARM edb
  451. //
  452. // wszREGDBTEMPDIRECTORY:
  453. // tmp.edb fixed name
  454. //
  455. // wszREGDBFLAGS:
  456. // wszFlags DBFLAGS_*
  457. //
  458. // Backed up files:
  459. // DB files (Attachments):
  460. // wszREGDBDIRECTORY: Your Name.EDB -- CSBFT_CERTSERVER_DATABASE
  461. //
  462. // Log files:
  463. // wszREGDBLOGDIRECTORY: EDB00001.log -- CSBFT_LOG
  464. // wszREGDBLOGDIRECTORY: EDB00002.log -- CSBFT_LOG
  465. // wszREGDBDIRECTORY: Your Name.pat -- CSBFT_PATCH_FILE
  466. //
  467. //+--------------------------------------------------------------------------
  468. ///// initialize database access
  469. HRESULT
  470. DBOpen(
  471. WCHAR const *pwszSanitizedName)
  472. {
  473. HRESULT hr = S_OK;
  474. DWORD cb;
  475. DWORD i;
  476. DWORD dwState;
  477. HKEY hkey = NULL;
  478. WCHAR wszTempDir[MAX_PATH];
  479. DWORD DBFlags;
  480. BOOL fRestarted;
  481. REGDBDIR adbdir[] =
  482. {
  483. { wszREGDBDIRECTORY, TRUE, g_wszDatabase, },
  484. { wszREGDBLOGDIRECTORY, TRUE, g_wszLogDir, },
  485. { wszREGDBSYSDIRECTORY, TRUE, g_wszSystemDir, },
  486. { wszREGDBTEMPDIRECTORY, TRUE, wszTempDir, },
  487. };
  488. // check machine setup status
  489. hr = GetSetupStatus(NULL, &dwState);
  490. _JumpIfError(hr, error, "GetSetupStatus");
  491. hr = RegOpenKey(HKEY_LOCAL_MACHINE, g_wszRegKeyConfigPath, &hkey);
  492. _JumpIfError(hr, error, "RegOpenKey(CAName)");
  493. // get info from registry
  494. for (i = 0; i < ARRAYSIZE(adbdir); i++)
  495. {
  496. cb = sizeof(WCHAR) * MAX_PATH;
  497. hr = RegQueryValueEx(
  498. hkey,
  499. adbdir[i].pwszRegName,
  500. NULL,
  501. NULL,
  502. (BYTE *) adbdir[i].pwszBuf,
  503. &cb);
  504. if ((HRESULT) ERROR_FILE_NOT_FOUND == hr && !adbdir[i].fMustExist)
  505. {
  506. adbdir[i].pwszBuf[0] = L'\0';
  507. hr = S_OK;
  508. }
  509. _JumpIfError(hr, error, "RegQueryValueEx(DB*Dir)");
  510. }
  511. if (wcslen(g_wszDatabase) +
  512. 1 +
  513. wcslen(pwszSanitizedName) +
  514. wcslen(wszDBFILENAMEEXT) >= ARRAYSIZE(g_wszDatabase))
  515. {
  516. hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
  517. _JumpErrorStr(hr, error, "g_wszDatabase", pwszSanitizedName);
  518. }
  519. wcscat(g_wszDatabase, L"\\");
  520. wcscat(g_wszDatabase, pwszSanitizedName);
  521. wcscat(g_wszDatabase, wszDBFILENAMEEXT);
  522. cb = sizeof(DBFlags);
  523. hr = RegQueryValueEx(
  524. hkey,
  525. wszREGDBFLAGS,
  526. NULL,
  527. NULL,
  528. (BYTE *) &DBFlags,
  529. &cb);
  530. if (S_OK != hr)
  531. {
  532. //_PrintErrorStr(hr, "RegQueryValueEx", wszREGDBFLAGS);
  533. DBFlags = DBFLAGS_DEFAULT;
  534. }
  535. DBFlags &= ~(DBFLAGS_READONLY | DBFLAGS_DISABLESNAPSHOTBACKUP);
  536. if (g_fCreateDB || (SETUP_CREATEDB_FLAG & dwState))
  537. {
  538. DBFlags |= DBFLAGS_CREATEIFNEEDED;
  539. }
  540. if (IF_NOSNAPSHOTBACKUP & g_InterfaceFlags)
  541. {
  542. DBFlags |= DBFLAGS_DISABLESNAPSHOTBACKUP;
  543. }
  544. hr = dbCheckRecoveryState(
  545. hkey,
  546. 2, // cSession
  547. DBFlags,
  548. g_wszCertSrvDotExe, // pwszEventSource
  549. g_wszLogDir, // pwszLogDir
  550. g_wszSystemDir, // pwszSystemDir
  551. wszTempDir); // pwszTempDir
  552. _JumpIfError(hr, error, "dbCheckRecoveryState");
  553. CONSOLEPRINT1((DBG_SS_CERTSRV, "Opening Database %ws\n", g_wszDatabase));
  554. __try
  555. {
  556. hr = CoCreateInstance(
  557. CLSID_CCertDB,
  558. NULL, // pUnkOuter
  559. CLSCTX_INPROC_SERVER,
  560. IID_ICertDB,
  561. (VOID **) &g_pCertDB);
  562. _LeaveIfError(hr, "CoCreateInstance(ICertDB)");
  563. // only perform Hash if the auditing is enabled
  564. if (AUDIT_FILTER_STARTSTOP & g_dwAuditFilter)
  565. {
  566. hr = myComputeMAC(g_wszDatabase, &g_pwszDBFileHash);
  567. // db file does not exist when starting the CA first time
  568. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  569. {
  570. _PrintErrorStr(hr, "Database file not found, can't calculate hash", g_wszDatabase);
  571. hr = S_OK;
  572. }
  573. _LeaveIfErrorStr(hr, "myComputeMAC", g_wszDatabase);
  574. }
  575. // S_FALSE means a DB schema change was made that requires a restart
  576. // to take effect. Open the DB a second time if S_FALSE is returned.
  577. fRestarted = FALSE;
  578. for (;;)
  579. {
  580. hr = g_pCertDB->Open(
  581. DBFlags, // Flags
  582. g_dwSessionCount, // cSession
  583. g_wszCertSrvDotExe, // pwszEventSource
  584. g_wszDatabase, // pwszDBFile
  585. g_wszLogDir, // pwszLogDir
  586. g_wszSystemDir, // pwszSystemDir
  587. wszTempDir); // pwszTempDir
  588. if (S_OK == hr)
  589. {
  590. break;
  591. }
  592. if (S_FALSE == hr && fRestarted)
  593. {
  594. _PrintError(hr, "Open");
  595. break;
  596. }
  597. if (S_FALSE != hr)
  598. {
  599. _LeaveError(hr, "Open");
  600. }
  601. hr = g_pCertDB->ShutDown(0);
  602. _PrintIfError(hr, "DB ShutDown");
  603. fRestarted = TRUE;
  604. }
  605. if (SETUP_CREATEDB_FLAG & dwState)
  606. {
  607. hr = SetSetupStatus(NULL, SETUP_CREATEDB_FLAG, FALSE);
  608. _LeaveIfError(hr, "SetSetupStatus");
  609. }
  610. hr = S_OK;
  611. CONSOLEPRINT0((DBG_SS_CERTSRV, "Database open\n"));
  612. }
  613. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  614. {
  615. }
  616. error:
  617. if (S_OK != hr)
  618. {
  619. if (NULL != g_pCertDB)
  620. {
  621. g_pCertDB->Release();
  622. g_pCertDB = NULL;
  623. }
  624. }
  625. if (NULL != hkey)
  626. {
  627. RegCloseKey(hkey);
  628. }
  629. return(hr);
  630. }
  631. HRESULT
  632. DBShutDown(
  633. IN BOOL fPendingNotify)
  634. {
  635. HRESULT hr = S_OK;
  636. if (NULL != g_pCertDB)
  637. {
  638. hr = g_pCertDB->ShutDown(fPendingNotify? CDBSHUTDOWN_PENDING : 0);
  639. if (!fPendingNotify)
  640. {
  641. g_pCertDB->Release();
  642. g_pCertDB = NULL;
  643. }
  644. }
  645. return(hr);
  646. }
  647. HRESULT
  648. dbRecoverAfterRestore(
  649. IN DWORD cSession,
  650. IN DWORD DBFlags,
  651. IN WCHAR const *pwszEventSource,
  652. IN WCHAR const *pwszLogDir,
  653. IN WCHAR const *pwszSystemDir,
  654. IN WCHAR const *pwszTempDir,
  655. IN WCHAR const *pwszCheckPointFile,
  656. IN WCHAR const *pwszLogPath,
  657. IN CSEDB_RSTMAPW rgrstmap[],
  658. IN LONG crstmap,
  659. IN WCHAR const *pwszBackupLogPath,
  660. IN DWORD genLow,
  661. IN DWORD genHigh)
  662. {
  663. HRESULT hr;
  664. ICertDBRestore *pCertDBRestore = NULL;
  665. hr = S_OK;
  666. __try
  667. {
  668. WCHAR *apwsz[2];
  669. hr = CoCreateInstance(
  670. CLSID_CCertDBRestore,
  671. NULL, // pUnkOuter
  672. CLSCTX_INPROC_SERVER,
  673. IID_ICertDBRestore,
  674. (VOID **) &pCertDBRestore);
  675. _LeaveIfError(hr, "CoCreateInstance(ICertDBRestore)");
  676. hr = pCertDBRestore->RecoverAfterRestore(
  677. cSession,
  678. DBFlags,
  679. pwszEventSource,
  680. pwszLogDir,
  681. pwszSystemDir,
  682. pwszTempDir,
  683. pwszCheckPointFile,
  684. pwszLogPath,
  685. rgrstmap,
  686. crstmap,
  687. pwszBackupLogPath,
  688. genLow,
  689. genHigh);
  690. _LeaveIfError(hr, "RecoverAfterRestore");
  691. apwsz[0] = wszREGDBLASTFULLBACKUP;
  692. apwsz[1] = wszREGDBLASTINCREMENTALBACKUP;
  693. hr = CertSrvSetRegistryFileTimeValue(
  694. TRUE,
  695. wszREGDBLASTRECOVERY,
  696. ARRAYSIZE(apwsz),
  697. apwsz);
  698. _PrintIfError(hr, "CertSrvSetRegistryFileTimeValue");
  699. hr = S_OK;
  700. }
  701. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  702. {
  703. }
  704. if (NULL != pCertDBRestore)
  705. {
  706. pCertDBRestore->Release();
  707. }
  708. return(hr);
  709. }
  710. HRESULT
  711. dbPerformRecovery(
  712. IN DWORD cSession,
  713. IN DWORD DBFlags,
  714. IN WCHAR const *pwszEventSource,
  715. IN WCHAR const *pwszLogDir,
  716. IN WCHAR const *pwszSystemDir,
  717. IN WCHAR const *pwszTempDir,
  718. IN WCHAR const *pwszCheckPointFile,
  719. IN WCHAR const *pwszLogPath,
  720. IN CSEDB_RSTMAPW rgrstmap[],
  721. IN LONG crstmap,
  722. IN WCHAR const *pwszBackupLogPath,
  723. IN unsigned long genLow,
  724. IN unsigned long genHigh,
  725. IN OUT BOOLEAN *pfRecoverJetDatabase)
  726. {
  727. HRESULT hr = S_OK;
  728. // Call into JET to let it munge the databases.
  729. // Note that the JET interpretation of LogPath and BackupLogPath is
  730. // totally wierd, and we want to pass in LogPath to both parameters.
  731. if (!*pfRecoverJetDatabase)
  732. {
  733. hr = dbRecoverAfterRestore(
  734. cSession,
  735. DBFlags,
  736. pwszEventSource,
  737. pwszLogDir,
  738. pwszSystemDir,
  739. pwszTempDir,
  740. pwszCheckPointFile,
  741. pwszLogPath,
  742. rgrstmap,
  743. crstmap,
  744. pwszBackupLogPath,
  745. genLow,
  746. genHigh);
  747. _JumpIfError(hr, error, "dbRecoverAfterRestore");
  748. }
  749. // Ok, we were able to recover the database. Let the other side of the
  750. // API know about it so it can do something "reasonable".
  751. *pfRecoverJetDatabase = TRUE;
  752. // Mark the DB as a restored version - Add any external notification here
  753. error:
  754. return(hr);
  755. }
  756. //+--------------------------------------------------------------------------
  757. // dbCheckRecoveryState -- recover a database after a restore if necessary.
  758. //
  759. // Parameters:
  760. // pwszParametersRoot - the root of the parameters section for the service in
  761. // the registry.
  762. //
  763. // Returns: HRESULT - S_OK if successful; error code if not.
  764. //
  765. // The NTBACKUP program will place a key at the location:
  766. // $(pwszParametersRoot)\Restore in Progress
  767. //
  768. // This key contains the following values:
  769. // BackupLogPath - The full path for the logs after a backup
  770. // CheckPointFilePath - The full path for the path that contains the checkpoint
  771. // *HighLogNumber - The maximum log file number found.
  772. // *LowLogNumber - The minimum log file number found.
  773. // LogPath - The current path for the logs.
  774. // JET_RstMap - Restore map for database - this is a REG_MULTISZ, where odd
  775. // entries go into the pwszDatabase field, and the even entries go into the
  776. // pwszNewDatabase field of a JET_RstMap
  777. // *JET_RstMap Size - The number of entries in the restoremap.
  778. //
  779. // * - These entries are REG_DWORD's. All others are REG_SZ's (except where
  780. // mentioned).
  781. //---------------------------------------------------------------------------
  782. HRESULT
  783. dbCheckRecoveryState(
  784. IN HKEY hkeyConfig,
  785. IN DWORD cSession,
  786. IN DWORD DBFlags,
  787. IN WCHAR const *pwszEventSource,
  788. IN WCHAR const *pwszLogDir,
  789. IN WCHAR const *pwszSystemDir,
  790. IN WCHAR const *pwszTempDir)
  791. {
  792. HRESULT hr;
  793. HKEY hkeyRestore = NULL;
  794. DWORD cb;
  795. WCHAR wszCheckPointFilePath[MAX_PATH];
  796. WCHAR wszBackupLogPath[MAX_PATH];
  797. WCHAR wszLogPath[MAX_PATH];
  798. WCHAR *pwszCheckPointFilePath;
  799. WCHAR *pwszBackupLogPath;
  800. WCHAR *pwszLogPath;
  801. WCHAR *pwszRestoreMap = NULL;
  802. CSEDB_RSTMAPW *pRstMap = NULL;
  803. LONG cRstMap;
  804. LONG i;
  805. DWORD genLow;
  806. DWORD genHigh;
  807. WCHAR *pwsz;
  808. DWORD dwType;
  809. HRESULT hrRestoreError;
  810. BOOLEAN fDatabaseRecovered = FALSE;
  811. WCHAR wszActiveLogPath[MAX_PATH];
  812. hr = dbRestoreRecoveryStateFromFile(pwszLogDir);
  813. _JumpIfError(hr, error, "dbRestoreRecoveryStateFromFile");
  814. hr = RegOpenKey(HKEY_LOCAL_MACHINE, wszREGKEYCONFIGRESTORE, &hkeyRestore);
  815. if (S_OK != hr)
  816. {
  817. // We want to ignore file_not_found - it is ok.
  818. if (hr == ERROR_FILE_NOT_FOUND)
  819. {
  820. hr = S_OK;
  821. }
  822. _PrintIfError(hr, "RegOpenKey");
  823. goto error;
  824. }
  825. CONSOLEPRINT0((DBG_SS_CERTSRV, "Started Database Recovery\n"));
  826. // If there's a restore in progress, then fail to perform any other
  827. // restore operations.
  828. dwType = REG_DWORD;
  829. cb = sizeof(DWORD);
  830. hr = RegQueryValueEx(
  831. hkeyRestore,
  832. wszREGRESTORESTATUS,
  833. 0,
  834. &dwType,
  835. (BYTE *) &hrRestoreError,
  836. &cb);
  837. if (S_OK == hr)
  838. {
  839. hr = hrRestoreError;
  840. _JumpError(hr, error, "hrRestoreError");
  841. }
  842. cb = sizeof(wszActiveLogPath);
  843. hr = RegQueryValueEx(
  844. hkeyConfig,
  845. wszREGDBLOGDIRECTORY,
  846. NULL,
  847. NULL,
  848. (BYTE *) wszActiveLogPath,
  849. &cb);
  850. _JumpIfErrorStr(hr, error, "RegQueryValueEx", wszREGDBLOGDIRECTORY);
  851. // We have now opened the restore-in-progress key. This means that we have
  852. // something to do now. Find out what it is. First, let's get the backup
  853. // log file path.
  854. dwType = REG_SZ;
  855. cb = sizeof(wszBackupLogPath);
  856. pwszBackupLogPath = wszBackupLogPath;
  857. hr = RegQueryValueEx(
  858. hkeyRestore,
  859. wszREGBACKUPLOGDIRECTORY,
  860. 0,
  861. &dwType,
  862. (BYTE *) wszBackupLogPath,
  863. &cb);
  864. if (S_OK != hr)
  865. {
  866. if (hr != ERROR_FILE_NOT_FOUND)
  867. {
  868. _JumpError(hr, error, "RegQueryValueEx");
  869. }
  870. pwszBackupLogPath = NULL;
  871. }
  872. // Then, the checkpoint file path.
  873. cb = sizeof(wszCheckPointFilePath);
  874. pwszCheckPointFilePath = wszCheckPointFilePath;
  875. hr = RegQueryValueEx(
  876. hkeyRestore,
  877. wszREGCHECKPOINTFILE,
  878. 0,
  879. &dwType,
  880. (BYTE *) wszCheckPointFilePath,
  881. &cb);
  882. if (S_OK != hr)
  883. {
  884. if (hr != ERROR_FILE_NOT_FOUND)
  885. {
  886. _JumpError(hr, error, "RegQueryValueEx");
  887. }
  888. pwszCheckPointFilePath = NULL;
  889. }
  890. // Then, the Log path.
  891. cb = sizeof(wszLogPath);
  892. pwszLogPath = wszLogPath;
  893. hr = RegQueryValueEx(
  894. hkeyRestore,
  895. wszREGLOGPATH,
  896. 0,
  897. &dwType,
  898. (BYTE *) wszLogPath,
  899. &cb);
  900. if (S_OK != hr)
  901. {
  902. if ((HRESULT) ERROR_FILE_NOT_FOUND != hr)
  903. {
  904. _JumpError(hr, error, "RegQueryValueEx");
  905. }
  906. pwszLogPath = NULL;
  907. }
  908. // Then, the low log number.
  909. dwType = REG_DWORD;
  910. cb = sizeof(genLow);
  911. hr = RegQueryValueEx(
  912. hkeyRestore,
  913. wszREGLOWLOGNUMBER,
  914. 0,
  915. &dwType,
  916. (BYTE *) &genLow,
  917. &cb);
  918. _JumpIfError(hr, error, "RegQueryValueEx");
  919. // And, the high log number.
  920. cb = sizeof(genHigh);
  921. hr = RegQueryValueEx(
  922. hkeyRestore,
  923. wszREGHIGHLOGNUMBER,
  924. 0,
  925. &dwType,
  926. (BYTE *) &genHigh,
  927. &cb);
  928. _JumpIfError(hr, error, "RegQueryValueEx");
  929. // Now determine if we had previously recovered the database.
  930. dwType = REG_BINARY;
  931. cb = sizeof(fDatabaseRecovered);
  932. hr = RegQueryValueEx(
  933. hkeyRestore,
  934. wszREGDATABASERECOVERED,
  935. 0,
  936. &dwType,
  937. &fDatabaseRecovered,
  938. &cb);
  939. if (S_OK != hr && (HRESULT) ERROR_FILE_NOT_FOUND != hr)
  940. {
  941. // If there was an error other than "value doesn't exist", bail.
  942. _JumpError(hr, error, "RegQueryValueEx");
  943. }
  944. // Now the tricky one. We want to get the restore map.
  945. // First we figure out how big it is.
  946. dwType = REG_DWORD;
  947. cb = sizeof(cRstMap);
  948. hr = RegQueryValueEx(
  949. hkeyRestore,
  950. wszREGRESTOREMAPCOUNT,
  951. 0,
  952. &dwType,
  953. (BYTE *) &cRstMap,
  954. &cb);
  955. _JumpIfError(hr, error, "RegQueryValueEx");
  956. pRstMap = (CSEDB_RSTMAPW *) LocalAlloc(
  957. LMEM_FIXED,
  958. sizeof(CSEDB_RSTMAPW) * cRstMap);
  959. if (NULL == pRstMap)
  960. {
  961. hr = E_OUTOFMEMORY;
  962. _JumpError(hr, error, "LocalAlloc");
  963. }
  964. // First find out how much memory is needed to hold the restore map.
  965. dwType = REG_MULTI_SZ;
  966. hr = RegQueryValueEx(
  967. hkeyRestore,
  968. wszREGRESTOREMAP,
  969. 0,
  970. &dwType,
  971. NULL,
  972. &cb);
  973. if (S_OK != hr && (HRESULT) ERROR_MORE_DATA != hr)
  974. {
  975. _JumpError(hr, error, "RegQueryValueEx");
  976. }
  977. pwszRestoreMap = (WCHAR *) LocalAlloc(LMEM_FIXED, cb + 2 * sizeof(WCHAR));
  978. if (NULL == pwszRestoreMap)
  979. {
  980. hr = E_OUTOFMEMORY;
  981. _JumpError(hr, error, "LocalAlloc");
  982. }
  983. hr = RegQueryValueEx(
  984. hkeyRestore,
  985. wszREGRESTOREMAP,
  986. 0,
  987. &dwType,
  988. (BYTE *) pwszRestoreMap,
  989. &cb);
  990. _JumpIfError(hr, error, "RegQueryValueEx");
  991. pwszRestoreMap[cb / sizeof(WCHAR)] = L'\0';
  992. pwszRestoreMap[cb / sizeof(WCHAR) + 1] = L'\0';
  993. pwsz = pwszRestoreMap;
  994. for (i = 0; i < cRstMap; i++)
  995. {
  996. if (L'\0' == *pwsz)
  997. {
  998. break;
  999. }
  1000. pRstMap[i].pwszDatabaseName = pwsz;
  1001. pwsz += wcslen(pwsz) + 1;
  1002. if (L'\0' == *pwsz)
  1003. {
  1004. break;
  1005. }
  1006. pRstMap[i].pwszNewDatabaseName = pwsz;
  1007. pwsz += wcslen(pwsz) + 1;
  1008. }
  1009. if (i < cRstMap || L'\0' != *pwsz)
  1010. {
  1011. hr = E_INVALIDARG;
  1012. _JumpError(hr, error, "Restore Map");
  1013. }
  1014. {
  1015. CertSrv::CAuditEvent event(SE_AUDITID_CERTSRV_RESTORESTART, g_dwAuditFilter);
  1016. hr = event.Report();
  1017. _JumpIfError(hr, error, "CAuditEvent::Report");
  1018. }
  1019. hr = dbPerformRecovery(
  1020. cSession,
  1021. DBFlags,
  1022. pwszEventSource,
  1023. pwszLogDir,
  1024. pwszSystemDir,
  1025. pwszTempDir,
  1026. pwszCheckPointFilePath,
  1027. NULL != pwszLogPath? pwszLogPath : wszActiveLogPath,
  1028. pRstMap,
  1029. cRstMap,
  1030. NULL != pwszBackupLogPath? pwszBackupLogPath : wszActiveLogPath,
  1031. genLow,
  1032. genHigh,
  1033. &fDatabaseRecovered);
  1034. if (S_OK != hr)
  1035. {
  1036. // The recovery failed. If recovering the database succeeded, flag it
  1037. // in the registry so we don't try again. Ignore RegSetValueEx errors,
  1038. // because the recovery error is more important.
  1039. RegSetValueEx(
  1040. hkeyRestore,
  1041. wszREGDATABASERECOVERED,
  1042. 0,
  1043. REG_BINARY,
  1044. (BYTE *) &fDatabaseRecovered,
  1045. sizeof(fDatabaseRecovered));
  1046. _JumpError(hr, error, "dbPerformRecovery");
  1047. }
  1048. {
  1049. CertSrv::CAuditEvent event(SE_AUDITID_CERTSRV_RESTOREEND, g_dwAuditFilter);
  1050. hr = event.Report();
  1051. _JumpIfError(hr, error, "CAuditEvent::Report");
  1052. }
  1053. CONSOLEPRINT0((DBG_SS_CERTSRV, "Completed Database Recovery\n"));
  1054. g_fDBRecovered = TRUE;
  1055. // Ok, we're all done. We can now delete the key, since we're done
  1056. // with it.
  1057. RegCloseKey(hkeyRestore);
  1058. hkeyRestore = NULL;
  1059. hr = RegDeleteKey(HKEY_LOCAL_MACHINE, wszREGKEYCONFIGRESTORE);
  1060. _JumpIfError(hr, error, "RegDeleteKey");
  1061. error:
  1062. if (NULL != pwszRestoreMap)
  1063. {
  1064. LocalFree(pwszRestoreMap);
  1065. }
  1066. if (NULL != pRstMap)
  1067. {
  1068. LocalFree(pRstMap);
  1069. }
  1070. if (NULL != hkeyRestore)
  1071. {
  1072. RegCloseKey(hkeyRestore);
  1073. }
  1074. return(hr);
  1075. }