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.

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