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.

3391 lines
75 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999
  5. //
  6. // File: backup.cpp
  7. //
  8. // Contents: Cert Server wrapper routines
  9. //
  10. //---------------------------------------------------------------------------
  11. #include <pch.cpp>
  12. #pragma hdrstop
  13. #include "certdb.h"
  14. #include "cscsp.h"
  15. #include <esent.h>
  16. #define __dwFILE__ __dwFILE_CERTLIB_BACKUP_CPP__
  17. #define _64k (64 * 1024)
  18. DWORD
  19. _64kBlocks(
  20. IN DWORD nFileSizeHigh,
  21. IN DWORD nFileSizeLow)
  22. {
  23. LARGE_INTEGER li;
  24. li.HighPart = nFileSizeHigh;
  25. li.LowPart = nFileSizeLow;
  26. return((DWORD) ((li.QuadPart + _64k - 1) / _64k));
  27. }
  28. HRESULT
  29. myLargeAlloc(
  30. OUT DWORD *pcbLargeAlloc,
  31. OUT BYTE **ppbLargeAlloc)
  32. {
  33. HRESULT hr;
  34. // at 512k the server begins doing efficient backups
  35. *pcbLargeAlloc = 512 * 1024;
  36. *ppbLargeAlloc = (BYTE *) VirtualAlloc(
  37. NULL,
  38. *pcbLargeAlloc,
  39. MEM_COMMIT,
  40. PAGE_READWRITE);
  41. if (NULL == *ppbLargeAlloc)
  42. {
  43. // couldn't alloc a large chunk? Try 64k...
  44. *pcbLargeAlloc = _64k;
  45. *ppbLargeAlloc = (BYTE *) VirtualAlloc(
  46. NULL,
  47. *pcbLargeAlloc,
  48. MEM_COMMIT,
  49. PAGE_READWRITE);
  50. if (NULL == *ppbLargeAlloc)
  51. {
  52. hr = myHLastError();
  53. _JumpError(hr, error, "VirtualAlloc");
  54. }
  55. }
  56. hr = S_OK;
  57. error:
  58. return(hr);
  59. }
  60. // Files to look for when checking for an existing DB, AND
  61. // Files to delete when clearing out a DB or DB Log directory:
  62. // Do NOT delete certsrv.mdb from Cert server 1.0!
  63. WCHAR const * const g_apwszDBFileMatchPatterns[] =
  64. {
  65. L"res*.log",
  66. TEXT(szDBBASENAMEPARM) L"*.log", // "edb*.log"
  67. TEXT(szDBBASENAMEPARM) L"*.chk", // "edb*.chk"
  68. L"*" wszDBFILENAMEEXT, // "*.edb"
  69. NULL
  70. };
  71. HRESULT
  72. myDeleteDBFilesInDir(
  73. IN WCHAR const *pwszDir)
  74. {
  75. HRESULT hr;
  76. WCHAR const * const *ppwsz;
  77. for (ppwsz = g_apwszDBFileMatchPatterns; NULL != *ppwsz; ppwsz++)
  78. {
  79. hr = myDeleteFilePattern(pwszDir, *ppwsz, FALSE);
  80. _JumpIfError(hr, error, "myDeleteFilePattern");
  81. }
  82. hr = S_OK;
  83. error:
  84. return(hr);
  85. }
  86. HRESULT
  87. DoFilesExistInDir(
  88. IN WCHAR const *pwszDir,
  89. IN WCHAR const *pwszPattern,
  90. OUT BOOL *pfFilesExist,
  91. OPTIONAL OUT WCHAR **ppwszFileInUse)
  92. {
  93. HRESULT hr;
  94. HANDLE hf = INVALID_HANDLE_VALUE;
  95. WCHAR *pwszFindPattern = NULL;
  96. WIN32_FIND_DATA wfd;
  97. *pfFilesExist = FALSE;
  98. if (NULL != ppwszFileInUse)
  99. {
  100. *ppwszFileInUse = NULL;
  101. }
  102. hr = myBuildPathAndExt(pwszDir, pwszPattern, NULL, &pwszFindPattern);
  103. _JumpIfError(hr, error, "myBuildPathAndExt");
  104. hf = FindFirstFile(pwszFindPattern, &wfd);
  105. if (INVALID_HANDLE_VALUE == hf)
  106. {
  107. hr = S_OK;
  108. goto error;
  109. }
  110. do
  111. {
  112. if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  113. {
  114. continue;
  115. }
  116. //printf("File: %ws\n", wfd.cFileName);
  117. *pfFilesExist = TRUE;
  118. if (NULL != ppwszFileInUse)
  119. {
  120. WCHAR *pwszFile;
  121. hr = myBuildPathAndExt(pwszDir, wfd.cFileName, NULL, &pwszFile);
  122. _JumpIfError(hr, error, "myBuildPathAndExt");
  123. if (myIsFileInUse(pwszFile))
  124. {
  125. DBGPRINT((
  126. DBG_SS_CERTLIB,
  127. "DoFilesExistInDir: File In Use: %ws\n",
  128. pwszFile));
  129. *ppwszFileInUse = pwszFile;
  130. hr = S_OK;
  131. goto error;
  132. }
  133. LocalFree(pwszFile);
  134. }
  135. } while (FindNextFile(hf, &wfd));
  136. hr = S_OK;
  137. error:
  138. if (INVALID_HANDLE_VALUE != hf)
  139. {
  140. FindClose(hf);
  141. }
  142. if (NULL != pwszFindPattern)
  143. {
  144. LocalFree(pwszFindPattern);
  145. }
  146. return(hr);
  147. }
  148. HRESULT
  149. myDoDBFilesExistInDir(
  150. IN WCHAR const *pwszDir,
  151. OUT BOOL *pfFilesExist,
  152. OPTIONAL OUT WCHAR **ppwszFileInUse)
  153. {
  154. HRESULT hr;
  155. WCHAR const * const *ppwsz;
  156. *pfFilesExist = FALSE;
  157. if (NULL != ppwszFileInUse)
  158. {
  159. *ppwszFileInUse = NULL;
  160. }
  161. hr = S_OK;
  162. for (ppwsz = g_apwszDBFileMatchPatterns; NULL != *ppwsz; ppwsz++)
  163. {
  164. BOOL fFilesExist;
  165. hr = DoFilesExistInDir(
  166. pwszDir,
  167. *ppwsz,
  168. &fFilesExist,
  169. ppwszFileInUse);
  170. _JumpIfError(hr, error, "DoFilesExistInDir");
  171. if (fFilesExist)
  172. {
  173. *pfFilesExist = TRUE;
  174. }
  175. if (NULL != ppwszFileInUse && NULL != *ppwszFileInUse)
  176. {
  177. break;
  178. }
  179. }
  180. CSASSERT(S_OK == hr);
  181. error:
  182. return(hr);
  183. }
  184. HRESULT
  185. DoDBFilesExistInRegDir(
  186. IN WCHAR const *pwszRegName,
  187. OUT BOOL *pfFilesExist,
  188. OPTIONAL OUT WCHAR **ppwszFileInUse)
  189. {
  190. HRESULT hr;
  191. WCHAR *pwszDir = NULL;
  192. *pfFilesExist = FALSE;
  193. if (NULL != ppwszFileInUse)
  194. {
  195. *ppwszFileInUse = NULL;
  196. }
  197. hr = myGetCertRegStrValue(NULL, NULL, NULL, pwszRegName, &pwszDir);
  198. if (S_OK != hr)
  199. {
  200. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  201. {
  202. // reg entry doesn't exist, that's fine
  203. goto done;
  204. }
  205. _JumpError(hr, error, "myGetCertRegStrValue");
  206. }
  207. hr = myDoDBFilesExistInDir(pwszDir, pfFilesExist, ppwszFileInUse);
  208. _JumpIfError(hr, error, "myDoDBFilesExistInDir");
  209. done:
  210. hr = S_OK;
  211. error:
  212. if (NULL != pwszDir)
  213. {
  214. LocalFree(pwszDir);
  215. }
  216. return(hr);
  217. }
  218. HRESULT
  219. BuildDBFileName(
  220. IN WCHAR const *pwszSanitizedName,
  221. OUT WCHAR **ppwszDBFile)
  222. {
  223. HRESULT hr;
  224. WCHAR *pwszDir = NULL;
  225. *ppwszDBFile = NULL;
  226. // get existing db path
  227. hr = myGetCertRegStrValue(NULL, NULL, NULL, wszREGDBDIRECTORY, &pwszDir);
  228. _JumpIfError(hr, error, "myGetCertRegStrValue");
  229. // form existing db file path
  230. hr = myBuildPathAndExt(
  231. pwszDir,
  232. pwszSanitizedName,
  233. wszDBFILENAMEEXT,
  234. ppwszDBFile);
  235. _JumpIfError(hr, error, "myBuildPathAndExt");
  236. error:
  237. if (NULL != pwszDir)
  238. {
  239. LocalFree(pwszDir);
  240. }
  241. return(hr);
  242. }
  243. WCHAR const * const g_apwszDBRegNames[] =
  244. {
  245. wszREGDBDIRECTORY,
  246. wszREGDBLOGDIRECTORY,
  247. wszREGDBSYSDIRECTORY,
  248. wszREGDBTEMPDIRECTORY,
  249. NULL
  250. };
  251. // Verify that the DB and DB Log directories in the registry contain existing
  252. // DB files, to decide whether the DB could be reused by cert server setup.
  253. // Also see if any of the DB files are in use -- we don't want to point to the
  254. // same directory as the DS DB and trash the DS, for example.
  255. HRESULT
  256. myDoDBFilesExist(
  257. IN WCHAR const *pwszSanitizedName,
  258. OUT BOOL *pfFilesExist,
  259. OPTIONAL OUT WCHAR **ppwszFileInUse)
  260. {
  261. HRESULT hr;
  262. WCHAR const * const *ppwsz;
  263. WCHAR *pwszDBFile = NULL;
  264. *pfFilesExist = FALSE;
  265. if (NULL != ppwszFileInUse)
  266. {
  267. *ppwszFileInUse = NULL;
  268. }
  269. // this is very primitive, just check for existence
  270. // get existing db file path
  271. hr = BuildDBFileName(pwszSanitizedName, &pwszDBFile);
  272. if (S_OK == hr)
  273. {
  274. // If the main DB file doesn't exist, there's no point in continuing!
  275. if (!myDoesFileExist(pwszDBFile))
  276. {
  277. CSASSERT(S_OK == hr);
  278. goto error;
  279. }
  280. *pfFilesExist = TRUE;
  281. if (NULL != ppwszFileInUse && myIsFileInUse(pwszDBFile))
  282. {
  283. *ppwszFileInUse = pwszDBFile;
  284. pwszDBFile = NULL;
  285. CSASSERT(S_OK == hr);
  286. goto error;
  287. }
  288. }
  289. else
  290. {
  291. _PrintError(hr, "BuildDBFileName");
  292. }
  293. for (ppwsz = g_apwszDBRegNames; NULL != *ppwsz; ppwsz++)
  294. {
  295. BOOL fFilesExist;
  296. hr = DoDBFilesExistInRegDir(*ppwsz, &fFilesExist, ppwszFileInUse);
  297. _JumpIfError(hr, error, "DoDBFilesExistInRegDir");
  298. if (fFilesExist)
  299. {
  300. *pfFilesExist = TRUE;
  301. }
  302. if (NULL != ppwszFileInUse && NULL != *ppwszFileInUse)
  303. {
  304. CSASSERT(S_OK == hr);
  305. goto error;
  306. }
  307. }
  308. CSASSERT(S_OK == hr);
  309. error:
  310. if (NULL != pwszDBFile)
  311. {
  312. LocalFree(pwszDBFile);
  313. }
  314. return(hr);
  315. }
  316. HRESULT
  317. BackupCopyDBFile(
  318. IN HCSBC hcsbc,
  319. IN WCHAR const *pwszDBFile,
  320. IN WCHAR const *pwszBackupFile,
  321. IN DWORD dwPercentCompleteBase,
  322. IN DWORD dwPercentCompleteDelta,
  323. OUT DWORD *pdwPercentComplete)
  324. {
  325. HRESULT hr;
  326. HRESULT hr2;
  327. HANDLE hFileBackup = INVALID_HANDLE_VALUE;
  328. BOOL fOpen = FALSE;
  329. LARGE_INTEGER licbFile;
  330. DWORD cbRead;
  331. DWORD cbWritten;
  332. DWORD dwPercentCompleteCurrent;
  333. DWORD ReadLoopMax;
  334. DWORD ReadLoopCurrent;
  335. DWORD cbLargeAlloc;
  336. BYTE *pbLargeAlloc = NULL;
  337. hr = myLargeAlloc(&cbLargeAlloc, &pbLargeAlloc);
  338. _JumpIfError(hr, error, "myLargeAlloc");
  339. //printf("Copy %ws to %ws\n", pwszDBFile, pwszBackupFile);
  340. hr = CertSrvBackupOpenFile(hcsbc, pwszDBFile, cbLargeAlloc, &licbFile);
  341. _JumpIfError(hr, error, "CertSrvBackupOpenFile");
  342. fOpen = TRUE;
  343. hFileBackup = CreateFile(
  344. pwszBackupFile,
  345. GENERIC_WRITE,
  346. 0,
  347. NULL,
  348. CREATE_NEW,
  349. 0,
  350. NULL);
  351. if (hFileBackup == INVALID_HANDLE_VALUE)
  352. {
  353. hr = myHLastError();
  354. _JumpErrorStr(hr, error, "CreateFile", pwszBackupFile);
  355. }
  356. dwPercentCompleteCurrent = dwPercentCompleteBase;
  357. ReadLoopMax =
  358. (DWORD) ((licbFile.QuadPart + cbLargeAlloc - 1) / cbLargeAlloc);
  359. //printf("BackupDBFile: Percent per Read = %u, read count = %u\n", dwPercentCompleteDelta / ReadLoopMax, ReadLoopMax);
  360. ReadLoopCurrent = 0;
  361. while (0 != licbFile.QuadPart)
  362. {
  363. hr = CertSrvBackupRead(hcsbc, pbLargeAlloc, cbLargeAlloc, &cbRead);
  364. _JumpIfError(hr, error, "CertSrvBackupRead");
  365. //printf("CertSrvBackupRead(%x)\n", cbRead);
  366. if (!WriteFile(hFileBackup, pbLargeAlloc, cbRead, &cbWritten, NULL))
  367. {
  368. hr = myHLastError();
  369. _JumpErrorStr(hr, error, "WriteFile", pwszBackupFile);
  370. }
  371. if (cbWritten != cbRead)
  372. {
  373. hr = HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
  374. _JumpErrorStr(hr, error, "WriteFile", pwszBackupFile);
  375. }
  376. licbFile.QuadPart -= cbRead;
  377. ReadLoopCurrent++;
  378. dwPercentCompleteCurrent =
  379. dwPercentCompleteBase +
  380. (ReadLoopCurrent * dwPercentCompleteDelta) / ReadLoopMax;
  381. CSASSERT(dwPercentCompleteCurrent <= dwPercentCompleteBase + dwPercentCompleteDelta);
  382. CSASSERT(*pdwPercentComplete <= dwPercentCompleteCurrent);
  383. *pdwPercentComplete = dwPercentCompleteCurrent;
  384. //printf("BackupDBFile: PercentComplete = %u\n", *pdwPercentComplete);
  385. }
  386. CSASSERT(*pdwPercentComplete <= dwPercentCompleteBase + dwPercentCompleteDelta);
  387. *pdwPercentComplete = dwPercentCompleteBase + dwPercentCompleteDelta;
  388. //printf("BackupDBFile: PercentComplete = %u (EOF)\n", *pdwPercentComplete);
  389. error:
  390. if (INVALID_HANDLE_VALUE != hFileBackup)
  391. {
  392. CloseHandle(hFileBackup);
  393. }
  394. if (fOpen)
  395. {
  396. hr2 = CertSrvBackupClose(hcsbc);
  397. _PrintIfError(hr2, "CertSrvBackupClose");
  398. }
  399. if (NULL != pbLargeAlloc)
  400. {
  401. VirtualFree(pbLargeAlloc, 0, MEM_RELEASE);
  402. }
  403. return(hr);
  404. }
  405. HRESULT
  406. BackupDBFileList(
  407. IN HCSBC hcsbc,
  408. IN BOOL fDBFiles,
  409. IN WCHAR const *pwszDir,
  410. OUT DWORD *pdwPercentComplete)
  411. {
  412. HRESULT hr;
  413. WCHAR *pwszzList = NULL;
  414. WCHAR const *pwsz;
  415. DWORD cfile;
  416. DWORD cb;
  417. WCHAR const *pwszFile;
  418. WCHAR wszPath[MAX_PATH];
  419. DWORD dwPercentCompleteCurrent;
  420. DWORD dwPercentComplete1File;
  421. if (fDBFiles)
  422. {
  423. hr = CertSrvBackupGetDatabaseNames(hcsbc, &pwszzList, &cb);
  424. _JumpIfError(hr, error, "CertSrvBackupGetDatabaseNames");
  425. }
  426. else
  427. {
  428. hr = CertSrvBackupGetBackupLogs(hcsbc, &pwszzList, &cb);
  429. _JumpIfError(hr, error, "CertSrvBackupGetBackupLogs");
  430. }
  431. // prefix complains this might happen, then deref'd below
  432. if (pwszzList == NULL)
  433. {
  434. hr = E_UNEXPECTED;
  435. _JumpError(hr, error, "BackupDBFileList");
  436. }
  437. cfile = 0;
  438. for (pwsz = pwszzList; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
  439. {
  440. cfile++;
  441. }
  442. if (0 != cfile)
  443. {
  444. dwPercentCompleteCurrent = 0;
  445. dwPercentComplete1File = 100 / cfile;
  446. //printf("BackupDBFileList: Percent per File = %u\n", dwPercentComplete1File);
  447. for (pwsz = pwszzList; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
  448. {
  449. pwszFile = wcsrchr(pwsz, L'\\');
  450. if (NULL == pwszFile)
  451. {
  452. pwszFile = pwsz;
  453. }
  454. else
  455. {
  456. pwszFile++;
  457. }
  458. wcscpy(wszPath, pwszDir);
  459. wcscat(wszPath, L"\\");
  460. wcscat(wszPath, pwszFile);
  461. DBGPRINT((
  462. DBG_SS_CERTLIBI,
  463. "BackupDBFileList: %x %ws -> %ws\n",
  464. *pwsz,
  465. &pwsz[1],
  466. wszPath));
  467. hr = BackupCopyDBFile(
  468. hcsbc,
  469. &pwsz[1],
  470. wszPath,
  471. dwPercentCompleteCurrent,
  472. dwPercentComplete1File,
  473. pdwPercentComplete);
  474. _JumpIfError(hr, error, "BackupCopyDBFile");
  475. dwPercentCompleteCurrent += dwPercentComplete1File;
  476. CSASSERT(*pdwPercentComplete == dwPercentCompleteCurrent);
  477. //printf("BackupDBFileList: PercentComplete = %u\n", *pdwPercentComplete);
  478. }
  479. }
  480. CSASSERT(*pdwPercentComplete <= 100);
  481. *pdwPercentComplete = 100;
  482. //printf("BackupDBFileList: PercentComplete = %u (END)\n", *pdwPercentComplete);
  483. hr = S_OK;
  484. error:
  485. if (NULL != pwszzList)
  486. {
  487. CertSrvBackupFree(pwszzList);
  488. }
  489. return(hr);
  490. }
  491. BOOL
  492. myIsDirEmpty(
  493. IN WCHAR const *pwszDir)
  494. {
  495. HANDLE hf;
  496. WIN32_FIND_DATA wfd;
  497. WCHAR wszpath[MAX_PATH];
  498. BOOL fEmpty = TRUE;
  499. wszpath[0] = L'\0';
  500. wcscpy(wszpath, pwszDir);
  501. wcscat(wszpath, L"\\*.*");
  502. hf = FindFirstFile(wszpath, &wfd);
  503. if (INVALID_HANDLE_VALUE != hf)
  504. {
  505. do {
  506. if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  507. {
  508. continue;
  509. }
  510. fEmpty = FALSE;
  511. //printf("File: %ws\n", wfd.cFileName);
  512. break;
  513. } while (FindNextFile(hf, &wfd));
  514. FindClose(hf);
  515. }
  516. return(fEmpty);
  517. }
  518. HRESULT
  519. myForceDirEmpty(
  520. IN WCHAR const *pwszDir)
  521. {
  522. HRESULT hr;
  523. HANDLE hf;
  524. WIN32_FIND_DATA wfd;
  525. WCHAR *pwszFile;
  526. WCHAR wszpath[MAX_PATH];
  527. wszpath[0] = L'\0';
  528. wcscpy(wszpath, pwszDir);
  529. wcscat(wszpath, L"\\*.*");
  530. pwszFile = &wszpath[wcslen(pwszDir)] + 1;
  531. hf = FindFirstFile(wszpath, &wfd);
  532. if (INVALID_HANDLE_VALUE == hf)
  533. {
  534. hr = myHLastError();
  535. _JumpIfError(hr, error, "FindFirstFile");
  536. }
  537. do {
  538. if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  539. {
  540. continue;
  541. }
  542. wcscpy(pwszFile, wfd.cFileName);
  543. //printf("File: %ws\n", wszpath);
  544. DeleteFile(wszpath);
  545. } while (FindNextFile(hf, &wfd));
  546. FindClose(hf);
  547. hr = S_OK;
  548. error:
  549. return(hr);
  550. }
  551. BOOL
  552. myIsDirectory(IN WCHAR const *pwszDirectoryPath)
  553. {
  554. WIN32_FILE_ATTRIBUTE_DATA data;
  555. return(
  556. GetFileAttributesEx(pwszDirectoryPath, GetFileExInfoStandard, &data) &&
  557. (FILE_ATTRIBUTE_DIRECTORY & data.dwFileAttributes));
  558. }
  559. BOOL
  560. myIsFileInUse(
  561. IN WCHAR const *pwszFile)
  562. {
  563. BOOL fInUse = FALSE;
  564. HANDLE hFile;
  565. hFile = CreateFile(
  566. pwszFile,
  567. GENERIC_WRITE, // dwDesiredAccess
  568. 0, // no share
  569. NULL, // lpSecurityAttributes
  570. OPEN_EXISTING, // open only & fail if doesn't exist
  571. 0, // dwFlagAndAttributes
  572. NULL); // hTemplateFile
  573. if (INVALID_HANDLE_VALUE == hFile)
  574. {
  575. if (ERROR_SHARING_VIOLATION == GetLastError())
  576. {
  577. fInUse = TRUE;
  578. }
  579. }
  580. else
  581. {
  582. CloseHandle(hFile);
  583. }
  584. return(fInUse);
  585. }
  586. HRESULT
  587. myCreateBackupDir(
  588. IN WCHAR const *pwszDir,
  589. IN BOOL fForceOverWrite)
  590. {
  591. HRESULT hr;
  592. if (!myIsDirectory(pwszDir))
  593. {
  594. if (!CreateDirectory(pwszDir, NULL))
  595. {
  596. hr = myHLastError();
  597. if (HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) != hr)
  598. {
  599. _JumpErrorStr(hr, error, "CreateDirectory", pwszDir);
  600. }
  601. } // else dir created successfully
  602. } // else dir already exists
  603. if (!myIsDirEmpty(pwszDir))
  604. {
  605. if (!fForceOverWrite)
  606. {
  607. hr = HRESULT_FROM_WIN32(ERROR_DIR_NOT_EMPTY);
  608. _JumpErrorStr(hr, error, "myIsDirEmpty", pwszDir);
  609. }
  610. hr = myForceDirEmpty(pwszDir);
  611. _JumpIfErrorStr(hr, error, "myForceDirEmpty", pwszDir);
  612. if (!myIsDirEmpty(pwszDir))
  613. {
  614. hr = HRESULT_FROM_WIN32(ERROR_DIR_NOT_EMPTY);
  615. _JumpErrorStr(hr, error, "myIsDirEmpty", pwszDir);
  616. }
  617. } // else is empty
  618. hr = S_OK;
  619. error:
  620. return(hr);
  621. }
  622. // if Flags & CDBBACKUP_VERIFYONLY, create and verify the target directory is empty
  623. HRESULT
  624. myBackupDB(
  625. IN WCHAR const *pwszConfig,
  626. IN DWORD Flags,
  627. IN WCHAR const *pwszBackupDir,
  628. OPTIONAL OUT DBBACKUPPROGRESS *pdbp)
  629. {
  630. HRESULT hr;
  631. HRESULT hr2;
  632. BOOL fServerOnline;
  633. HCSBC hcsbc;
  634. BOOL fBegin = FALSE;
  635. WCHAR *pwszPathDBDir = NULL;
  636. WCHAR *pwszDATFile = NULL;
  637. WCHAR *pwszzFileList = NULL;
  638. DWORD cbList;
  639. DBBACKUPPROGRESS dbp;
  640. LONG grbitJet;
  641. LONG BackupFlags;
  642. BOOL fImpersonating = FALSE;
  643. if (NULL == pwszConfig)
  644. {
  645. hr = E_INVALIDARG;
  646. _JumpError(hr, error, "NULL pwszConfig");
  647. }
  648. if (NULL == pdbp)
  649. {
  650. pdbp = &dbp;
  651. }
  652. ZeroMemory(pdbp, sizeof(*pdbp));
  653. if (!ImpersonateSelf(SecurityImpersonation))
  654. {
  655. hr = myHLastError();
  656. _JumpError(hr, error, "ImpersonateSelf");
  657. }
  658. fImpersonating = TRUE;
  659. hr = myEnablePrivilege(SE_BACKUP_NAME, TRUE);
  660. _JumpIfError(hr, error, "myEnablePrivilege");
  661. if (NULL == pwszBackupDir)
  662. {
  663. hr = E_POINTER;
  664. _JumpError(hr, error, "NULL parm");
  665. }
  666. if (~CDBBACKUP_BACKUPVALID & Flags)
  667. {
  668. hr = E_INVALIDARG;
  669. _JumpError(hr, error, "Flags");
  670. }
  671. if (!myIsDirectory(pwszBackupDir))
  672. {
  673. if (!CreateDirectory(pwszBackupDir, NULL))
  674. {
  675. hr = myHLastError();
  676. if (HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) != hr)
  677. {
  678. _JumpError(hr, error, "CreateDirectory");
  679. }
  680. }
  681. }
  682. hr = myBuildPathAndExt(
  683. pwszBackupDir,
  684. wszDBBACKUPSUBDIR,
  685. NULL,
  686. &pwszPathDBDir);
  687. _JumpIfError(hr, error, "myBuildPathAndExt");
  688. hr = myCreateBackupDir(
  689. pwszPathDBDir,
  690. (CDBBACKUP_OVERWRITE & Flags)? TRUE : FALSE);
  691. _JumpIfError(hr, error, "myCreateBackupDir");
  692. //if (NULL != pwszConfig)
  693. if (0 == (Flags & CDBBACKUP_VERIFYONLY))
  694. {
  695. hr = CertSrvIsServerOnline(pwszConfig, &fServerOnline);
  696. _JumpIfError(hr, error, "CertSrvIsServerOnline");
  697. //printf("Cert Server Online -> %d\n", fServerOnline);
  698. if (!fServerOnline)
  699. {
  700. hr = HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE);
  701. _JumpError(hr, error, "CertSrvIsServerOnline");
  702. }
  703. BackupFlags = CSBACKUP_TYPE_FULL;
  704. grbitJet = 0;
  705. if (CDBBACKUP_INCREMENTAL & Flags)
  706. {
  707. grbitJet |= JET_bitBackupIncremental;
  708. BackupFlags = CSBACKUP_TYPE_LOGS_ONLY;
  709. }
  710. if (CDBBACKUP_KEEPOLDLOGS & Flags)
  711. {
  712. // JetBeginExternalBackup can't handle setting this bit
  713. // grbitJet |= JET_bitKeepOldLogs;
  714. }
  715. hr = CertSrvBackupPrepare(pwszConfig, grbitJet, BackupFlags, &hcsbc);
  716. _JumpIfError(hr, error, "CertSrvBackupPrepare");
  717. fBegin = TRUE;
  718. if (0 == (CDBBACKUP_INCREMENTAL & Flags))
  719. {
  720. hr = CertSrvRestoreGetDatabaseLocations(hcsbc, &pwszzFileList, &cbList);
  721. _JumpIfError(hr, error, "CertSrvRestoreGetDatabaseLocations");
  722. hr = myBuildPathAndExt(
  723. pwszPathDBDir,
  724. wszDBBACKUPCERTBACKDAT,
  725. NULL,
  726. &pwszDATFile);
  727. _JumpIfError(hr, error, "myBuildPathAndExt");
  728. hr = EncodeToFileW(
  729. pwszDATFile,
  730. (BYTE const *) pwszzFileList,
  731. cbList,
  732. CRYPT_STRING_BINARY);
  733. _JumpIfError(hr, error, "EncodeToFileW");
  734. hr = BackupDBFileList(
  735. hcsbc,
  736. TRUE,
  737. pwszPathDBDir,
  738. &pdbp->dwDBPercentComplete);
  739. _JumpIfError(hr, error, "BackupDBFileList(DB)");
  740. }
  741. else
  742. {
  743. pdbp->dwDBPercentComplete = 100;
  744. }
  745. //printf("DB Done: dwDBPercentComplete = %u\n", pdbp->dwDBPercentComplete);
  746. hr = BackupDBFileList(
  747. hcsbc,
  748. FALSE,
  749. pwszPathDBDir,
  750. &pdbp->dwLogPercentComplete);
  751. _JumpIfError(hr, error, "BackupDBFileList(Log)");
  752. //printf("Log Done: dwLogPercentComplete = %u\n", pdbp->dwLogPercentComplete);
  753. if (0 == (CDBBACKUP_KEEPOLDLOGS & Flags))
  754. {
  755. hr = CertSrvBackupTruncateLogs(hcsbc);
  756. _JumpIfError(hr, error, "CertSrvBackupTruncateLogs");
  757. }
  758. pdbp->dwTruncateLogPercentComplete = 100;
  759. //printf("Truncate Done: dwTruncateLogPercentComplete = %u\n", pdbp->dwTruncateLogPercentComplete);
  760. }
  761. error:
  762. if (NULL != pwszzFileList)
  763. {
  764. CertSrvBackupFree(pwszzFileList);
  765. }
  766. if (fBegin)
  767. {
  768. hr2 = CertSrvBackupEnd(hcsbc);
  769. _PrintIfError(hr2, "CertSrvBackupEnd");
  770. if (S_OK == hr)
  771. {
  772. hr = hr2;
  773. }
  774. }
  775. if (NULL != pwszDATFile)
  776. {
  777. LocalFree(pwszDATFile);
  778. }
  779. if (NULL != pwszPathDBDir)
  780. {
  781. LocalFree(pwszPathDBDir);
  782. }
  783. if (fImpersonating)
  784. {
  785. myEnablePrivilege(SE_BACKUP_NAME, FALSE);
  786. RevertToSelf();
  787. }
  788. return(hr);
  789. }
  790. // Verify the backup file names only, and return the log file numeric range.
  791. HRESULT
  792. myVerifyBackupDirectory(
  793. IN WCHAR const *pwszConfig,
  794. IN DWORD Flags,
  795. IN WCHAR const *pwszPathDBDir,
  796. OUT DWORD *plogMin,
  797. OUT DWORD *plogMax,
  798. OUT DWORD *pc64kDBBlocks, // 64k blocks in DB files to be restored
  799. OUT DWORD *pc64kLogBlocks) // 64k blocks in Log files to be restored
  800. {
  801. HRESULT hr;
  802. HANDLE hf = INVALID_HANDLE_VALUE;
  803. WIN32_FIND_DATA wfd;
  804. WCHAR wszpath[2 * MAX_PATH];
  805. WCHAR wszfile[MAX_PATH];
  806. BOOL fSawEDBFile = FALSE;
  807. BOOL fSawDatFile = FALSE;
  808. DWORD cLogFiles = 0;
  809. WCHAR *pwszCA;
  810. WCHAR *pwszRevertCA = NULL;
  811. WCHAR *pwszSanitizedCA = NULL;
  812. WCHAR *pwszExt;
  813. WCHAR *pwsz;
  814. DWORD log;
  815. *plogMin = MAXDWORD;
  816. *plogMax = 0;
  817. *pc64kDBBlocks = 0;
  818. *pc64kLogBlocks = 0;
  819. wszpath[0] = L'\0';
  820. pwszCA = wcschr(pwszConfig, L'\\');
  821. if (NULL != pwszCA)
  822. {
  823. pwszCA++; // point to CA Name
  824. hr = myRevertSanitizeName(pwszCA, &pwszRevertCA);
  825. _JumpIfError(hr, error, "myRevertSanitizeName");
  826. hr = mySanitizeName(pwszRevertCA, &pwszSanitizedCA);
  827. _JumpIfError(hr, error, "mySanitizeName");
  828. }
  829. wcscpy(wszpath, pwszPathDBDir);
  830. wcscat(wszpath, L"\\*.*");
  831. hf = FindFirstFile(wszpath, &wfd);
  832. if (INVALID_HANDLE_VALUE == hf)
  833. {
  834. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  835. _JumpError(hr, error, "missing backup files");
  836. }
  837. hr = HRESULT_FROM_WIN32(ERROR_DIRECTORY);
  838. do {
  839. if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  840. {
  841. continue;
  842. }
  843. //printf("File: %ws\n", wfd.cFileName);
  844. wcscpy(wszfile, wfd.cFileName);
  845. pwszExt = wcsrchr(wszfile, L'.');
  846. if (NULL == pwszExt)
  847. {
  848. _JumpError(hr, error, "file missing extension");
  849. }
  850. *pwszExt++ = L'\0';
  851. if (0 == lstrcmpi(&wszLOGFILENAMEEXT[1], pwszExt))
  852. {
  853. if (0 != _wcsnicmp(wszfile, wszDBBASENAMEPARM, 3))
  854. {
  855. _JumpErrorStr(hr, error, "bad log prefix", wfd.cFileName);
  856. }
  857. for (pwsz = &wszfile[3]; L'\0' != *pwsz; pwsz++)
  858. {
  859. if (!iswxdigit(*pwsz))
  860. {
  861. _JumpErrorStr(hr, error, "bad name digit", wfd.cFileName);
  862. }
  863. }
  864. log = wcstoul(&wszfile[3], NULL, 16);
  865. if (log > *plogMax)
  866. {
  867. //printf("Log %x: max = %x -> %x\n", log, *plogMax, log);
  868. *plogMax = log;
  869. }
  870. if (log < *plogMin)
  871. {
  872. //printf("Log %x: min = %x -> %x\n", log, *plogMin, log);
  873. *plogMin = log;
  874. }
  875. *pc64kLogBlocks += _64kBlocks(wfd.nFileSizeHigh, wfd.nFileSizeLow);
  876. cLogFiles++;
  877. }
  878. else
  879. if (0 == lstrcmpi(&wszDBFILENAMEEXT[1], pwszExt))
  880. {
  881. if (fSawEDBFile)
  882. {
  883. _JumpError(hr, error, "multiple *.edb files");
  884. }
  885. if (NULL != pwszSanitizedCA &&
  886. 0 != lstrcmpi(wszfile, pwszSanitizedCA))
  887. {
  888. _PrintErrorStr(hr, "expected base name", pwszSanitizedCA);
  889. _JumpErrorStr(hr, error, "base name mismatch", wfd.cFileName);
  890. }
  891. *pc64kDBBlocks += _64kBlocks(wfd.nFileSizeHigh, wfd.nFileSizeLow);
  892. fSawEDBFile = TRUE;
  893. }
  894. else
  895. if (0 == lstrcmpi(&wszDATFILENAMEEXT[1], pwszExt))
  896. {
  897. if (fSawDatFile)
  898. {
  899. _JumpError(hr, error, "multiple *.dat files");
  900. }
  901. if (lstrcmpi(wfd.cFileName, wszDBBACKUPCERTBACKDAT))
  902. {
  903. _JumpErrorStr(hr, error, "unexpected file", wfd.cFileName);
  904. }
  905. fSawDatFile = TRUE;
  906. }
  907. else
  908. {
  909. _JumpErrorStr(hr, error, "unexpected extension", wfd.cFileName);
  910. }
  911. } while (FindNextFile(hf, &wfd));
  912. //printf("clog=%u: %u - %u edb=%u\n", cLogFiles, *plogMin, *plogMax, fSawEDBFile);
  913. if (0 == cLogFiles)
  914. {
  915. _JumpError(hr, error, "missing log file(s)");
  916. }
  917. if (0 == (CDBBACKUP_INCREMENTAL & Flags))
  918. {
  919. if (!fSawEDBFile || !fSawDatFile)
  920. {
  921. _JumpError(hr, error, "missing full backup file(s)");
  922. }
  923. }
  924. else
  925. {
  926. if (fSawEDBFile || fSawDatFile)
  927. {
  928. _JumpError(hr, error, "unexpected incremental backup file(s)");
  929. }
  930. }
  931. if (*plogMax - *plogMin + 1 != cLogFiles)
  932. {
  933. _JumpError(hr, error, "missing log file(s)");
  934. }
  935. hr = S_OK;
  936. error:
  937. if (NULL != pwszRevertCA)
  938. {
  939. LocalFree(pwszRevertCA);
  940. }
  941. if (NULL != pwszSanitizedCA)
  942. {
  943. LocalFree(pwszSanitizedCA);
  944. }
  945. if (INVALID_HANDLE_VALUE != hf)
  946. {
  947. FindClose(hf);
  948. }
  949. return(hr);
  950. }
  951. HRESULT
  952. myGetRegUNCDBDir(
  953. IN HKEY hkey,
  954. IN WCHAR const *pwszReg,
  955. OPTIONAL IN WCHAR const *pwszServer,
  956. IN WCHAR const **ppwszUNCDir)
  957. {
  958. HRESULT hr;
  959. DWORD dwType;
  960. DWORD cb;
  961. WCHAR *pwszDir = NULL;
  962. WCHAR *pwszUNCDir;
  963. *ppwszUNCDir = NULL;
  964. hr = RegQueryValueEx(hkey, pwszReg, NULL, &dwType, NULL, &cb);
  965. if (S_OK != hr)
  966. {
  967. hr = myHError(hr);
  968. _JumpErrorStr(hr, error, "RegQueryValueEx", pwszReg);
  969. }
  970. pwszDir = (WCHAR *) LocalAlloc(LMEM_FIXED, cb);
  971. if (NULL == pwszDir)
  972. {
  973. hr = E_OUTOFMEMORY;
  974. _JumpError(hr, error, "LocalAlloc");
  975. }
  976. hr = RegQueryValueEx(hkey, pwszReg, NULL, &dwType, (BYTE *) pwszDir, &cb);
  977. if (S_OK != hr)
  978. {
  979. hr = myHError(hr);
  980. _JumpErrorStr(hr, error, "RegQueryValueEx", pwszReg);
  981. }
  982. hr = myConvertLocalPathToUNC(pwszServer, pwszDir, &pwszUNCDir);
  983. _JumpIfError(hr, error, "myConvertLocalPathToUNC");
  984. *ppwszUNCDir = pwszUNCDir;
  985. error:
  986. if (NULL != pwszDir)
  987. {
  988. LocalFree(pwszDir);
  989. }
  990. return(hr);
  991. }
  992. HRESULT
  993. myCopyUNCPath(
  994. IN WCHAR const *pwszIn,
  995. OPTIONAL IN WCHAR const *pwszDnsName,
  996. OUT WCHAR const **ppwszOut)
  997. {
  998. HRESULT hr;
  999. WCHAR *pwszOut;
  1000. WCHAR const *pwsz;
  1001. *ppwszOut = NULL;
  1002. if (L'\\' != pwszIn[0] || L'\\' != pwszIn[1])
  1003. {
  1004. hr = E_INVALIDARG;
  1005. _JumpError(hr, error, "bad parm");
  1006. }
  1007. if (NULL == pwszDnsName)
  1008. {
  1009. hr = myConvertUNCPathToLocal(pwszIn, &pwszOut);
  1010. _JumpIfError(hr, error, "myConvertUNCPathToLocal");
  1011. }
  1012. else
  1013. {
  1014. pwsz = wcschr(&pwszIn[2], L'\\');
  1015. if (NULL == pwsz)
  1016. {
  1017. hr = E_INVALIDARG;
  1018. _JumpError(hr, error, "bad parm");
  1019. }
  1020. pwszOut = (WCHAR *) LocalAlloc(
  1021. LMEM_FIXED,
  1022. (2 + wcslen(pwszDnsName) + wcslen(pwsz) + 1) * sizeof(WCHAR));
  1023. if (NULL == pwszOut)
  1024. {
  1025. hr = E_OUTOFMEMORY;
  1026. _JumpError(hr, error, "LocalAlloc");
  1027. }
  1028. wcscpy(pwszOut, L"\\\\");
  1029. wcscat(pwszOut, pwszDnsName);
  1030. wcscat(pwszOut, pwsz);
  1031. }
  1032. *ppwszOut = pwszOut;
  1033. hr = S_OK;
  1034. error:
  1035. return(hr);
  1036. }
  1037. HRESULT
  1038. myGetDBPaths(
  1039. IN WCHAR const *pwszConfig,
  1040. OPTIONAL IN WCHAR const *pwszLogPath,
  1041. OPTIONAL IN WCHAR const *pwszzFileList,
  1042. OUT WCHAR const **ppwszDBDir,
  1043. OUT WCHAR const **ppwszLogDir,
  1044. OUT WCHAR const **ppwszSystemDir)
  1045. {
  1046. HRESULT hr;
  1047. HKEY hkey = NULL;
  1048. WCHAR *pwszDnsName = NULL;
  1049. WCHAR *pwszRegPath = NULL;
  1050. WCHAR *pwszDBDir = NULL;
  1051. WCHAR const *pwsz;
  1052. WCHAR const *pwszT;
  1053. BOOL fLocal;
  1054. *ppwszDBDir = NULL;
  1055. *ppwszLogDir = NULL;
  1056. *ppwszSystemDir = NULL;
  1057. hr = myIsConfigLocal(pwszConfig, NULL, &fLocal);
  1058. _JumpIfError(hr, error, "myIsConfigLocal");
  1059. if (fLocal)
  1060. {
  1061. pwszConfig = NULL;
  1062. }
  1063. else
  1064. {
  1065. hr = myGetMachineDnsName(&pwszDnsName);
  1066. _JumpIfError(hr, error, "myGetMachineDnsName");
  1067. }
  1068. hr = myRegOpenRelativeKey(
  1069. fLocal? NULL : pwszConfig,
  1070. L"",
  1071. 0,
  1072. &pwszRegPath,
  1073. NULL, // ppwszName
  1074. &hkey);
  1075. _JumpIfErrorStr(hr, error, "myRegOpenRelativeKey", pwszConfig);
  1076. // Find old database path:
  1077. pwszT = NULL;
  1078. if (NULL != pwszzFileList)
  1079. {
  1080. for (pwsz = pwszzFileList; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
  1081. {
  1082. if (CSBFT_CERTSERVER_DATABASE == *pwsz)
  1083. {
  1084. pwsz++;
  1085. pwszT = wcsrchr(pwsz, L'\\');
  1086. break;
  1087. }
  1088. }
  1089. }
  1090. if (NULL != pwszT)
  1091. {
  1092. DWORD cwc = SAFE_SUBTRACT_POINTERS(pwszT, pwsz);
  1093. pwszDBDir = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR));
  1094. if (NULL == pwszDBDir)
  1095. {
  1096. hr = E_OUTOFMEMORY;
  1097. _JumpError(hr, error, "LocalAlloc");
  1098. }
  1099. CopyMemory(pwszDBDir, pwsz, cwc * sizeof(WCHAR));
  1100. pwszDBDir[cwc] = L'\0';
  1101. hr = myCopyUNCPath(pwszDBDir, pwszDnsName, ppwszDBDir);
  1102. _JumpIfError(hr, error, "myCopyUNCPath");
  1103. }
  1104. else
  1105. {
  1106. hr = myGetRegUNCDBDir(hkey, wszREGDBDIRECTORY, pwszDnsName, ppwszDBDir);
  1107. _JumpIfError(hr, error, "myGetRegUNCDBDir");
  1108. }
  1109. if (NULL != pwszLogPath)
  1110. {
  1111. hr = myCopyUNCPath(pwszLogPath, pwszDnsName, ppwszLogDir);
  1112. _JumpIfError(hr, error, "myCopyUNCPath");
  1113. }
  1114. else
  1115. {
  1116. hr = myGetRegUNCDBDir(
  1117. hkey,
  1118. wszREGDBLOGDIRECTORY,
  1119. pwszDnsName,
  1120. ppwszLogDir);
  1121. _JumpIfError(hr, error, "myGetRegUNCDBDir");
  1122. }
  1123. hr = myGetRegUNCDBDir(
  1124. hkey,
  1125. wszREGDBSYSDIRECTORY,
  1126. pwszDnsName,
  1127. ppwszSystemDir);
  1128. _JumpIfError(hr, error, "myGetRegUNCDBDir");
  1129. error:
  1130. if (S_OK != hr)
  1131. {
  1132. if (NULL != *ppwszDBDir)
  1133. {
  1134. LocalFree(const_cast<WCHAR *>(*ppwszDBDir));
  1135. *ppwszDBDir = NULL;
  1136. }
  1137. if (NULL != *ppwszLogDir)
  1138. {
  1139. LocalFree(const_cast<WCHAR *>(*ppwszLogDir));
  1140. *ppwszLogDir = NULL;
  1141. }
  1142. if (NULL != *ppwszSystemDir)
  1143. {
  1144. LocalFree(const_cast<WCHAR *>(*ppwszSystemDir));
  1145. *ppwszSystemDir = NULL;
  1146. }
  1147. }
  1148. if (NULL != hkey)
  1149. {
  1150. RegCloseKey(hkey);
  1151. }
  1152. if (NULL != pwszDBDir)
  1153. {
  1154. LocalFree(pwszDBDir);
  1155. }
  1156. if (NULL != pwszRegPath)
  1157. {
  1158. LocalFree(pwszRegPath);
  1159. }
  1160. if (NULL != pwszDnsName)
  1161. {
  1162. LocalFree(pwszDnsName);
  1163. }
  1164. return(hr);
  1165. }
  1166. HRESULT
  1167. RestoreCopyFile(
  1168. IN BOOL fForceOverWrite,
  1169. IN WCHAR const *pwszSourceDir,
  1170. IN WCHAR const *pwszTargetDir,
  1171. IN WCHAR const *pwszFile,
  1172. IN DWORD nFileSizeHigh,
  1173. IN DWORD nFileSizeLow,
  1174. IN DWORD c64kBlocksTotal, // total file size
  1175. IN OUT DWORD *pc64kBlocksCurrent, // current file size sum
  1176. IN OUT DWORD *pdwPercentComplete)
  1177. {
  1178. HRESULT hr;
  1179. WCHAR *pwszSource = NULL;
  1180. WCHAR *pwszTarget = NULL;
  1181. HANDLE hTarget = INVALID_HANDLE_VALUE;
  1182. HANDLE hSource = INVALID_HANDLE_VALUE;
  1183. DWORD dwPercentCompleteCurrent;
  1184. LARGE_INTEGER licb;
  1185. LARGE_INTEGER licbRead;
  1186. DWORD cbRead;
  1187. DWORD cbWritten;
  1188. DWORD cbLargeAlloc;
  1189. BYTE *pbLargeAlloc = NULL;
  1190. DWORD c64kBlocksFile;
  1191. DWORD dwPercentComplete;
  1192. licb.HighPart = nFileSizeHigh;
  1193. licb.LowPart = nFileSizeLow;
  1194. hr = myBuildPathAndExt(pwszSourceDir, pwszFile, NULL, &pwszSource);
  1195. _JumpIfError(hr, error, "myBuildPathAndExt");
  1196. hr = myBuildPathAndExt(pwszTargetDir, pwszFile, NULL, &pwszTarget);
  1197. _JumpIfError(hr, error, "myBuildPathAndExt");
  1198. hr = myLargeAlloc(&cbLargeAlloc, &pbLargeAlloc);
  1199. _JumpIfError(hr, error, "myLargeAlloc");
  1200. hSource = CreateFile(
  1201. pwszSource,
  1202. GENERIC_READ,
  1203. 0,
  1204. NULL,
  1205. OPEN_EXISTING,
  1206. 0,
  1207. NULL);
  1208. if (hSource == INVALID_HANDLE_VALUE)
  1209. {
  1210. hr = myHLastError();
  1211. _JumpErrorStr(hr, error, "CreateFile", pwszSource);
  1212. }
  1213. hTarget = CreateFile(
  1214. pwszTarget,
  1215. GENERIC_WRITE,
  1216. 0,
  1217. NULL,
  1218. fForceOverWrite? CREATE_ALWAYS : CREATE_NEW,
  1219. 0,
  1220. NULL);
  1221. if (hTarget == INVALID_HANDLE_VALUE)
  1222. {
  1223. hr = myHLastError();
  1224. _JumpErrorStr(hr, error, "CreateFile", pwszTarget);
  1225. }
  1226. licbRead.QuadPart = 0;
  1227. c64kBlocksFile = 0;
  1228. while (licbRead.QuadPart < licb.QuadPart)
  1229. {
  1230. if (!ReadFile(hSource, pbLargeAlloc, cbLargeAlloc, &cbRead, NULL))
  1231. {
  1232. hr = myHLastError();
  1233. _JumpError(hr, error, "ReadFile");
  1234. }
  1235. //printf("ReadFile(%x)\n", cbRead);
  1236. if (!WriteFile(hTarget, pbLargeAlloc, cbRead, &cbWritten, NULL))
  1237. {
  1238. hr = myHLastError();
  1239. _JumpErrorStr(hr, error, "WriteFile", pwszTarget);
  1240. }
  1241. if (cbWritten != cbRead)
  1242. {
  1243. hr = HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
  1244. _JumpErrorStr(hr, error, "WriteFile", pwszTarget);
  1245. }
  1246. licbRead.QuadPart += cbRead;
  1247. c64kBlocksFile = _64kBlocks(licbRead.HighPart, licbRead.LowPart);
  1248. dwPercentComplete =
  1249. (100 * (c64kBlocksFile + *pc64kBlocksCurrent)) / c64kBlocksTotal;
  1250. CSASSERT(*pdwPercentComplete <= dwPercentComplete);
  1251. *pdwPercentComplete = dwPercentComplete;
  1252. //printf("RestoreCopyFile0: PercentComplete = %u\n", *pdwPercentComplete);
  1253. }
  1254. *pc64kBlocksCurrent += c64kBlocksFile;
  1255. dwPercentComplete = (100 * *pc64kBlocksCurrent) / c64kBlocksTotal;
  1256. CSASSERT(*pdwPercentComplete <= dwPercentComplete);
  1257. *pdwPercentComplete = dwPercentComplete;
  1258. //printf("RestoreCopyFile1: PercentComplete = %u\n", *pdwPercentComplete);
  1259. hr = S_OK;
  1260. error:
  1261. if (INVALID_HANDLE_VALUE != hTarget)
  1262. {
  1263. CloseHandle(hTarget);
  1264. }
  1265. if (INVALID_HANDLE_VALUE != hSource)
  1266. {
  1267. CloseHandle(hSource);
  1268. }
  1269. if (NULL != pwszSource)
  1270. {
  1271. LocalFree(pwszSource);
  1272. }
  1273. if (NULL != pwszTarget)
  1274. {
  1275. LocalFree(pwszTarget);
  1276. }
  1277. if (NULL != pbLargeAlloc)
  1278. {
  1279. VirtualFree(pbLargeAlloc, 0, MEM_RELEASE);
  1280. }
  1281. return(hr);
  1282. }
  1283. HRESULT
  1284. RestoreCopyFilePattern(
  1285. IN BOOL fForceOverWrite,
  1286. IN WCHAR const *pwszSourceDir,
  1287. IN WCHAR const *pwszTargetDir,
  1288. IN WCHAR const *pwszFilePattern,
  1289. IN DWORD c64kBlocksTotal, // total file size
  1290. IN OUT DWORD *pc64kBlocksCurrent, // current file size sum
  1291. IN OUT DWORD *pdwPercentComplete)
  1292. {
  1293. HRESULT hr;
  1294. WCHAR *pwszPattern = NULL;
  1295. HANDLE hf = INVALID_HANDLE_VALUE;
  1296. WIN32_FIND_DATA wfd;
  1297. hr = myBuildPathAndExt(pwszSourceDir, pwszFilePattern, NULL, &pwszPattern);
  1298. _JumpIfError(hr, error, "myBuildPathAndExt");
  1299. hf = FindFirstFile(pwszPattern, &wfd);
  1300. if (INVALID_HANDLE_VALUE == hf)
  1301. {
  1302. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  1303. _JumpErrorStr(hr, error, "missing source files", pwszPattern);
  1304. }
  1305. hr = HRESULT_FROM_WIN32(ERROR_DIRECTORY);
  1306. do {
  1307. if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  1308. {
  1309. continue;
  1310. }
  1311. //printf("File: %ws\n", wfd.cFileName);
  1312. hr = RestoreCopyFile(
  1313. fForceOverWrite,
  1314. pwszSourceDir, // source dir
  1315. pwszTargetDir, // target dir
  1316. wfd.cFileName,
  1317. wfd.nFileSizeHigh,
  1318. wfd.nFileSizeLow,
  1319. c64kBlocksTotal, // total file size
  1320. pc64kBlocksCurrent, // current file size sum
  1321. pdwPercentComplete);
  1322. _JumpIfError(hr, error, "RestoreCopyFile");
  1323. } while (FindNextFile(hf, &wfd));
  1324. hr = S_OK;
  1325. error:
  1326. if (INVALID_HANDLE_VALUE != hf)
  1327. {
  1328. FindClose(hf);
  1329. }
  1330. if (NULL != pwszPattern)
  1331. {
  1332. LocalFree(pwszPattern);
  1333. }
  1334. return(hr);
  1335. }
  1336. HRESULT
  1337. myRestoreDBFiles(
  1338. IN WCHAR const *pwszConfig,
  1339. IN DWORD Flags,
  1340. IN WCHAR const *pwszBackupDir,
  1341. OPTIONAL IN WCHAR const *pwszLogPath,
  1342. OPTIONAL IN WCHAR const *pwszzFileList, // NULL if incremental restore
  1343. IN DWORD c64kDBBlocks,
  1344. IN DWORD c64kLogBlocks,
  1345. OPTIONAL OUT DBBACKUPPROGRESS *pdbp)
  1346. {
  1347. HRESULT hr;
  1348. DWORD i;
  1349. #define IDIR_DB 0
  1350. #define IDIR_LOG 1
  1351. #define IDIR_SYSTEM 2
  1352. WCHAR const *apwszDirs[3] = { NULL, NULL, NULL };
  1353. DWORD c64kBlocksCurrent;
  1354. BOOL fForceOverWrite = 0 != (CDBBACKUP_OVERWRITE & Flags);
  1355. WCHAR *pwszFileInUse = NULL;
  1356. // Get DB, Log & System paths from registry
  1357. hr = myGetDBPaths(
  1358. pwszConfig,
  1359. pwszLogPath,
  1360. pwszzFileList,
  1361. &apwszDirs[IDIR_DB],
  1362. &apwszDirs[IDIR_LOG],
  1363. &apwszDirs[IDIR_SYSTEM]);
  1364. _JumpIfError(hr, error, "myGetDBPaths");
  1365. DBGPRINT((DBG_SS_CERTLIBI, "DBDir: %ws\n", apwszDirs[IDIR_DB]));
  1366. DBGPRINT((DBG_SS_CERTLIBI, "LogDir: %ws\n", apwszDirs[IDIR_LOG]));
  1367. DBGPRINT((DBG_SS_CERTLIBI, "SysDir: %ws\n", apwszDirs[IDIR_SYSTEM]));
  1368. CSASSERT((NULL == pwszzFileList) ^ (0 == (CDBBACKUP_INCREMENTAL & Flags)));
  1369. for (i = 0; i < ARRAYSIZE(apwszDirs); i++)
  1370. {
  1371. BOOL fFilesExist;
  1372. if (!myIsDirectory(apwszDirs[i]))
  1373. {
  1374. hr = HRESULT_FROM_WIN32(ERROR_DIRECTORY);
  1375. _JumpErrorStr(hr, error, "not a directory", apwszDirs[i]);
  1376. }
  1377. hr = myDoDBFilesExistInDir(apwszDirs[i], &fFilesExist, &pwszFileInUse);
  1378. _JumpIfError(hr, error, "myDoDBFilesExistInDir");
  1379. if (NULL != pwszFileInUse)
  1380. {
  1381. _PrintErrorStr(
  1382. HRESULT_FROM_WIN32(ERROR_BUSY),
  1383. "myDoDBFilesExistInDir",
  1384. pwszFileInUse);
  1385. }
  1386. if (!fFilesExist)
  1387. {
  1388. if (CDBBACKUP_INCREMENTAL & Flags)
  1389. {
  1390. // Incremental restore -- some DB files should already exist
  1391. hr = HRESULT_FROM_WIN32(ERROR_DIRECTORY);
  1392. _JumpErrorStr(hr, error, "myDoDBFilesExistInDir", apwszDirs[i]);
  1393. }
  1394. }
  1395. else if (0 == (CDBBACKUP_INCREMENTAL & Flags))
  1396. {
  1397. // Full restore -- no DB files should exist yet
  1398. if (!fForceOverWrite)
  1399. {
  1400. hr = HRESULT_FROM_WIN32(ERROR_DIR_NOT_EMPTY);
  1401. _JumpErrorStr(
  1402. hr,
  1403. error,
  1404. "myDoDBFilesExistInDir",
  1405. NULL != pwszFileInUse? pwszFileInUse : apwszDirs[i]);
  1406. }
  1407. hr = myDeleteDBFilesInDir(apwszDirs[i]);
  1408. if (S_OK != hr)
  1409. {
  1410. _PrintErrorStr(hr, "myDeleteDBFilesInDir", apwszDirs[i]);
  1411. }
  1412. }
  1413. }
  1414. // copy files to appropriate target directories
  1415. if (0 == (CDBBACKUP_INCREMENTAL & Flags))
  1416. {
  1417. c64kBlocksCurrent = 0;
  1418. hr = RestoreCopyFilePattern(
  1419. fForceOverWrite,
  1420. pwszBackupDir, // source dir
  1421. apwszDirs[IDIR_DB], // target dir
  1422. L"*" wszDBFILENAMEEXT, // match pattern
  1423. c64kDBBlocks,
  1424. &c64kBlocksCurrent, // current total file size
  1425. &pdbp->dwDBPercentComplete);
  1426. _JumpIfError(hr, error, "RestoreCopyFile");
  1427. CSASSERT(c64kDBBlocks == c64kBlocksCurrent);
  1428. }
  1429. CSASSERT(100 >= pdbp->dwDBPercentComplete);
  1430. pdbp->dwDBPercentComplete = 100;
  1431. c64kBlocksCurrent = 0;
  1432. hr = RestoreCopyFilePattern(
  1433. fForceOverWrite,
  1434. pwszBackupDir, // source dir
  1435. apwszDirs[IDIR_LOG], // target dir
  1436. L"*" wszLOGFILENAMEEXT, // match pattern
  1437. c64kLogBlocks,
  1438. &c64kBlocksCurrent, // current total file size
  1439. &pdbp->dwLogPercentComplete);
  1440. _JumpIfError(hr, error, "RestoreCopyFile");
  1441. CSASSERT(c64kLogBlocks == c64kBlocksCurrent);
  1442. CSASSERT(100 >= pdbp->dwLogPercentComplete);
  1443. pdbp->dwLogPercentComplete = 100;
  1444. CSASSERT(100 >= pdbp->dwTruncateLogPercentComplete);
  1445. pdbp->dwTruncateLogPercentComplete = 100;
  1446. hr = S_OK;
  1447. error:
  1448. if (NULL != pwszFileInUse)
  1449. {
  1450. LocalFree(pwszFileInUse);
  1451. }
  1452. for (i = 0; i < ARRAYSIZE(apwszDirs); i++)
  1453. {
  1454. if (NULL != apwszDirs[i])
  1455. {
  1456. LocalFree(const_cast<WCHAR *>(apwszDirs[i]));
  1457. }
  1458. }
  1459. return(hr);
  1460. }
  1461. HRESULT
  1462. myDeleteRestoreInProgressKey(
  1463. IN WCHAR const *pwszConfig)
  1464. {
  1465. HRESULT hr;
  1466. HKEY hkey = NULL;
  1467. WCHAR *pwszRegPath = NULL;
  1468. hr = myRegOpenRelativeKey(
  1469. pwszConfig,
  1470. L"",
  1471. RORKF_CREATESUBKEYS,
  1472. &pwszRegPath,
  1473. NULL, // ppwszName
  1474. &hkey);
  1475. _JumpIfErrorStr(hr, error, "myRegOpenRelativeKey", pwszConfig);
  1476. hr = RegDeleteKey(hkey, wszREGKEYRESTOREINPROGRESS);
  1477. _JumpIfError(hr, error, "RegDeleteKey");
  1478. error:
  1479. if (NULL != hkey)
  1480. {
  1481. RegCloseKey(hkey);
  1482. }
  1483. if (NULL != pwszRegPath)
  1484. {
  1485. LocalFree(pwszRegPath);
  1486. }
  1487. return(hr);
  1488. }
  1489. // If CDBBACKUP_VERIFYONLY, only verify the passed directory contains valid
  1490. // files. If pwszBackupDir is NULL, delete the RestoreInProgress registry key.
  1491. HRESULT
  1492. myRestoreDB(
  1493. IN WCHAR const *pwszConfig,
  1494. IN DWORD Flags,
  1495. OPTIONAL IN WCHAR const *pwszBackupDir,
  1496. OPTIONAL IN WCHAR const *pwszCheckPointFilePath,
  1497. OPTIONAL IN WCHAR const *pwszLogPath,
  1498. OPTIONAL IN WCHAR const *pwszBackupLogPath,
  1499. OPTIONAL OUT DBBACKUPPROGRESS *pdbp)
  1500. {
  1501. HRESULT hr;
  1502. HRESULT hr2;
  1503. WCHAR buf[MAX_PATH];
  1504. WCHAR *pwszPathDBDir = NULL;
  1505. WCHAR *pwszDATFile = NULL;
  1506. WCHAR *pwszzFileList = NULL;
  1507. DWORD cbList;
  1508. CSEDB_RSTMAP RstMap[1];
  1509. DWORD crstmap = 0;
  1510. WCHAR *pwszFile;
  1511. DWORD logMin;
  1512. DWORD logMax;
  1513. HCSBC hcsbc;
  1514. BOOL fBegin = FALSE;
  1515. BOOL fImpersonating = FALSE;
  1516. DBBACKUPPROGRESS dbp;
  1517. DWORD c64kDBBlocks; // 64k blocks in DB files to be restored
  1518. DWORD c64kLogBlocks; // 64k blocks in Log files to be restored
  1519. if (NULL == pdbp)
  1520. {
  1521. pdbp = &dbp;
  1522. }
  1523. ZeroMemory(pdbp, sizeof(*pdbp));
  1524. if (!ImpersonateSelf(SecurityImpersonation))
  1525. {
  1526. hr = myHLastError();
  1527. _JumpError(hr, error, "ImpersonateSelf");
  1528. }
  1529. fImpersonating = TRUE;
  1530. hr = myEnablePrivilege(SE_RESTORE_NAME, TRUE);
  1531. _JumpIfError(hr, error, "myEnablePrivilege");
  1532. hr = myEnablePrivilege(SE_BACKUP_NAME, TRUE);
  1533. _JumpIfError(hr, error, "myEnablePrivilege");
  1534. if (NULL == pwszConfig ||
  1535. ((CDBBACKUP_VERIFYONLY & Flags) && NULL == pwszBackupDir))
  1536. {
  1537. hr = E_POINTER;
  1538. _JumpError(hr, error, "NULL parm");
  1539. }
  1540. if (NULL != pwszBackupDir)
  1541. {
  1542. if (!GetFullPathName(pwszBackupDir, ARRAYSIZE(buf), buf, &pwszFile))
  1543. {
  1544. hr = myHLastError();
  1545. _JumpError(hr, error, "GetFullPathName");
  1546. }
  1547. hr = myBuildPathAndExt(buf, wszDBBACKUPSUBDIR, NULL, &pwszPathDBDir);
  1548. _JumpIfError(hr, error, "myBuildPathAndExt");
  1549. hr = myVerifyBackupDirectory(
  1550. pwszConfig,
  1551. Flags,
  1552. pwszPathDBDir,
  1553. &logMin,
  1554. &logMax,
  1555. &c64kDBBlocks,
  1556. &c64kLogBlocks);
  1557. _JumpIfError(hr, error, "myVerifyBackupDirectory");
  1558. DBGPRINT((
  1559. DBG_SS_CERTLIBI,
  1560. "c64kBlocks=%u+%u\n",
  1561. c64kDBBlocks,
  1562. c64kLogBlocks));
  1563. if (0 == (CDBBACKUP_INCREMENTAL & Flags))
  1564. {
  1565. hr = myBuildPathAndExt(
  1566. pwszPathDBDir,
  1567. wszDBBACKUPCERTBACKDAT,
  1568. NULL,
  1569. &pwszDATFile);
  1570. _JumpIfError(hr, error, "myBuildPathAndExt");
  1571. hr = DecodeFileW(
  1572. pwszDATFile,
  1573. (BYTE **) &pwszzFileList,
  1574. &cbList,
  1575. CRYPT_STRING_BINARY);
  1576. _JumpIfError(hr, error, "DecodeFileW");
  1577. if (2 * sizeof(WCHAR) >= cbList ||
  1578. L'\0' != pwszzFileList[cbList/sizeof(WCHAR) - 1] ||
  1579. L'\0' != pwszzFileList[cbList/sizeof(WCHAR) - 2])
  1580. {
  1581. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1582. _JumpError(hr, error, "pwszzFileList malformed");
  1583. }
  1584. RstMap[0].pwszDatabaseName = pwszzFileList;
  1585. RstMap[0].pwszNewDatabaseName = pwszzFileList;
  1586. crstmap = 1;
  1587. }
  1588. if (0 == (CDBBACKUP_VERIFYONLY & Flags))
  1589. {
  1590. hr = myRestoreDBFiles(
  1591. pwszConfig,
  1592. Flags,
  1593. pwszPathDBDir,
  1594. pwszLogPath,
  1595. pwszzFileList,
  1596. c64kDBBlocks,
  1597. c64kLogBlocks,
  1598. pdbp);
  1599. _JumpIfError(hr, error, "myRestoreDBFiles");
  1600. hr = CertSrvRestorePrepare(pwszConfig, CSRESTORE_TYPE_FULL, &hcsbc);
  1601. _JumpIfError(hr, error, "CertSrvRestorePrepare");
  1602. fBegin = TRUE;
  1603. hr = CertSrvRestoreRegister(
  1604. hcsbc,
  1605. pwszCheckPointFilePath,
  1606. pwszLogPath,
  1607. 0 == crstmap? NULL : RstMap,
  1608. crstmap,
  1609. pwszBackupLogPath,
  1610. logMin,
  1611. logMax);
  1612. // When running only as backup operator, we don't have rights
  1613. // in the registry and CertSrvRestoreRegister fails with access
  1614. // denied. We try to mark for restore through a file.
  1615. if (E_ACCESSDENIED == hr)
  1616. {
  1617. hr = CertSrvRestoreRegisterThroughFile(
  1618. hcsbc,
  1619. pwszCheckPointFilePath,
  1620. pwszLogPath,
  1621. 0 == crstmap? NULL : RstMap,
  1622. crstmap,
  1623. pwszBackupLogPath,
  1624. logMin,
  1625. logMax);
  1626. _JumpIfError(hr, error, "CertSrvRestoreRegisterThroughFile");
  1627. }
  1628. else
  1629. {
  1630. _JumpIfError(hr, error, "CertSrvRestoreRegister");
  1631. hr = CertSrvRestoreRegisterComplete(hcsbc, S_OK);
  1632. _JumpIfError(hr, error, "CertSrvRestoreRegisterComplete");
  1633. }
  1634. }
  1635. }
  1636. else if (0 == (CDBBACKUP_VERIFYONLY & Flags))
  1637. {
  1638. hr = myDeleteRestoreInProgressKey(pwszConfig);
  1639. _JumpIfError(hr, error, "myDeleteRestoreInProgressKey");
  1640. }
  1641. hr = S_OK;
  1642. error:
  1643. if (fBegin)
  1644. {
  1645. hr2 = CertSrvRestoreEnd(hcsbc);
  1646. _PrintIfError(hr2, "CertSrvBackupEnd");
  1647. if (S_OK == hr)
  1648. {
  1649. hr = hr2;
  1650. }
  1651. }
  1652. if (NULL != pwszzFileList)
  1653. {
  1654. LocalFree(pwszzFileList);
  1655. }
  1656. if (NULL != pwszDATFile)
  1657. {
  1658. LocalFree(pwszDATFile);
  1659. }
  1660. if (NULL != pwszPathDBDir)
  1661. {
  1662. LocalFree(pwszPathDBDir);
  1663. }
  1664. if (fImpersonating)
  1665. {
  1666. myEnablePrivilege(SE_BACKUP_NAME, FALSE);
  1667. myEnablePrivilege(SE_RESTORE_NAME, FALSE);
  1668. RevertToSelf();
  1669. }
  1670. return(hr);
  1671. }
  1672. HRESULT
  1673. myPFXExportCertStore(
  1674. IN HCERTSTORE hStore,
  1675. OUT CRYPT_DATA_BLOB *ppfx,
  1676. IN WCHAR const *pwszPassword,
  1677. IN DWORD dwFlags)
  1678. {
  1679. HRESULT hr;
  1680. ppfx->pbData = NULL;
  1681. if (!PFXExportCertStore(hStore, ppfx, pwszPassword, dwFlags))
  1682. {
  1683. hr = myHLastError();
  1684. _JumpError(hr, error, "PFXExportCertStore");
  1685. }
  1686. ppfx->pbData = (BYTE *) LocalAlloc(LMEM_FIXED, ppfx->cbData);
  1687. if (NULL == ppfx->pbData)
  1688. {
  1689. hr = E_OUTOFMEMORY;
  1690. _JumpError(hr, error, "no memory for PFX blob");
  1691. }
  1692. if (!PFXExportCertStore(hStore, ppfx, pwszPassword, dwFlags))
  1693. {
  1694. hr = myHLastError();
  1695. _JumpError(hr, error, "PFXExportCertStore");
  1696. }
  1697. hr = S_OK;
  1698. error:
  1699. return(hr);
  1700. }
  1701. ////////////////////////////////////////////////////////////////////////////
  1702. //
  1703. ////////////////////////////////////////////////////////////////////////////
  1704. HRESULT
  1705. myAddChainToMemoryStore(
  1706. IN HCERTSTORE hMemoryStore,
  1707. IN CERT_CONTEXT const *pCertContext)
  1708. {
  1709. HRESULT hr;
  1710. DWORD i;
  1711. CERT_CHAIN_CONTEXT const *pCertChainContext = NULL;
  1712. CERT_CHAIN_PARA CertChainPara;
  1713. CERT_SIMPLE_CHAIN *pSimpleChain;
  1714. ZeroMemory(&CertChainPara, sizeof(CertChainPara));
  1715. CertChainPara.cbSize = sizeof(CertChainPara);
  1716. if (!CertGetCertificateChain(
  1717. HCCE_LOCAL_MACHINE,
  1718. pCertContext,
  1719. NULL,
  1720. NULL,
  1721. &CertChainPara,
  1722. 0,
  1723. NULL,
  1724. &pCertChainContext))
  1725. {
  1726. hr = myHLastError();
  1727. _JumpError(hr, error, "CertGetCertificateChain");
  1728. }
  1729. // make sure there is at least 1 simple chain
  1730. if (0 == pCertChainContext->cChain)
  1731. {
  1732. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  1733. _JumpError(hr, error, "pCertChainContext->cChain");
  1734. }
  1735. pSimpleChain = pCertChainContext->rgpChain[0];
  1736. for (i = 0; i < pSimpleChain->cElement; i++)
  1737. {
  1738. if (!CertAddCertificateContextToStore(
  1739. hMemoryStore,
  1740. pSimpleChain->rgpElement[i]->pCertContext,
  1741. CERT_STORE_ADD_REPLACE_EXISTING,
  1742. NULL))
  1743. {
  1744. hr = myHLastError();
  1745. _JumpError(hr, error, "CertAddCertificateContextToStore");
  1746. }
  1747. }
  1748. hr = S_OK;
  1749. error:
  1750. if (pCertChainContext != NULL)
  1751. {
  1752. CertFreeCertificateChain(pCertChainContext);
  1753. }
  1754. return(hr);
  1755. }
  1756. HRESULT
  1757. SaveCACertChainToMemoryStore(
  1758. IN WCHAR const *pwszSanitizedName,
  1759. IN DWORD iCert,
  1760. IN HCERTSTORE hMyStore,
  1761. IN HCERTSTORE hTempMemoryStore)
  1762. {
  1763. HRESULT hr;
  1764. CERT_CONTEXT const *pccCA = NULL;
  1765. CRYPT_KEY_PROV_INFO *pkpi = NULL;
  1766. DWORD NameId;
  1767. hr = myFindCACertByHashIndex(
  1768. hMyStore,
  1769. pwszSanitizedName,
  1770. CSRH_CASIGCERT,
  1771. iCert,
  1772. &NameId,
  1773. &pccCA);
  1774. _JumpIfError(hr, error, "myFindCACertByHashIndex");
  1775. hr = myRepairCertKeyProviderInfo(pccCA, TRUE, &pkpi);
  1776. if (S_OK != hr)
  1777. {
  1778. if (CRYPT_E_NOT_FOUND != hr)
  1779. {
  1780. _JumpError(hr, error, "myRepairCertKeyProviderInfo");
  1781. }
  1782. }
  1783. else if (NULL != pkpi)
  1784. {
  1785. BOOL fMatchingKey;
  1786. hr = myVerifyPublicKey(
  1787. pccCA,
  1788. FALSE,
  1789. NULL, // pKeyProvInfo
  1790. NULL, // pPublicKeyInfo
  1791. &fMatchingKey);
  1792. if (S_OK != hr)
  1793. {
  1794. if (!IsHrSkipPrivateKey(hr))
  1795. {
  1796. _JumpError(hr, error, "myVerifyPublicKey");
  1797. }
  1798. _PrintError2(hr, "myVerifyPublicKey", hr);
  1799. }
  1800. else if (!fMatchingKey)
  1801. {
  1802. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1803. _JumpError(hr, error, "Key doesn't match cert");
  1804. }
  1805. }
  1806. // Begin Chain Building
  1807. hr = myAddChainToMemoryStore(hTempMemoryStore, pccCA);
  1808. _JumpIfError(hr, error, "myAddChainToMemoryStore");
  1809. // End Chain Building
  1810. error:
  1811. if (NULL != pkpi)
  1812. {
  1813. LocalFree(pkpi);
  1814. }
  1815. if (NULL != pccCA)
  1816. {
  1817. CertFreeCertificateContext(pccCA);
  1818. }
  1819. return(hr);
  1820. }
  1821. HRESULT
  1822. myCertServerExportPFX(
  1823. IN WCHAR const *pwszCA,
  1824. IN WCHAR const *pwszBackupDir,
  1825. IN WCHAR const *pwszPassword,
  1826. IN BOOL fForceOverWrite,
  1827. IN BOOL fMustExportPrivateKeys,
  1828. OPTIONAL OUT WCHAR **ppwszPFXFile)
  1829. {
  1830. HRESULT hr;
  1831. HCERTSTORE hMyStore = NULL;
  1832. HCERTSTORE hTempMemoryStore = NULL;
  1833. CRYPT_DATA_BLOB pfx;
  1834. WCHAR *pwszPFXFile = NULL;
  1835. BOOL fImpersonating = FALSE;
  1836. WCHAR *pwszSanitizedCA = NULL;
  1837. WCHAR *pwszRevertCA = NULL;
  1838. DWORD cCACert;
  1839. DWORD cCACertSaved;
  1840. DWORD i;
  1841. pfx.pbData = NULL;
  1842. if (!ImpersonateSelf(SecurityImpersonation))
  1843. {
  1844. hr = myHLastError();
  1845. _JumpError(hr, error, "ImpersonateSelf");
  1846. }
  1847. fImpersonating = TRUE;
  1848. hr = myEnablePrivilege(SE_BACKUP_NAME, TRUE);
  1849. _JumpIfError(hr, error, "myEnablePrivilege");
  1850. if (NULL != ppwszPFXFile)
  1851. {
  1852. *ppwszPFXFile = NULL;
  1853. }
  1854. while (TRUE)
  1855. {
  1856. hr = mySanitizeName(pwszCA, &pwszSanitizedCA);
  1857. _JumpIfError(hr, error, "mySanitizeName");
  1858. // get CA cert count
  1859. hr = myGetCARegHashCount(pwszSanitizedCA, CSRH_CASIGCERT, &cCACert);
  1860. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr &&
  1861. NULL == pwszRevertCA)
  1862. {
  1863. LocalFree(pwszSanitizedCA);
  1864. pwszSanitizedCA = NULL;
  1865. hr = myRevertSanitizeName(pwszCA, &pwszRevertCA);
  1866. _JumpIfError(hr, error, "myRevertSanitizeName");
  1867. pwszCA = pwszRevertCA;
  1868. continue;
  1869. }
  1870. _JumpIfError(hr, error, "myGetCARegHashCount");
  1871. if (NULL != pwszRevertCA)
  1872. {
  1873. DBGPRINT((
  1874. DBG_SS_CERTLIB,
  1875. "myCertServerExportPFX called with Sanitized Name: %ws\n",
  1876. pwszSanitizedCA));
  1877. }
  1878. break;
  1879. }
  1880. if (!myIsDirectory(pwszBackupDir))
  1881. {
  1882. if (!CreateDirectory(pwszBackupDir, NULL))
  1883. {
  1884. hr = myHLastError();
  1885. if (HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) != hr)
  1886. {
  1887. _JumpError(hr, error, "CreateDirectory");
  1888. }
  1889. }
  1890. }
  1891. pwszPFXFile = (WCHAR *) LocalAlloc(
  1892. LMEM_FIXED,
  1893. (wcslen(pwszBackupDir) +
  1894. 1 +
  1895. wcslen(pwszSanitizedCA) +
  1896. ARRAYSIZE(wszPFXFILENAMEEXT)) *
  1897. sizeof(WCHAR));
  1898. if (NULL == pwszPFXFile)
  1899. {
  1900. hr = E_OUTOFMEMORY;
  1901. _JumpError(hr, error, "LocalAlloc");
  1902. }
  1903. wcscpy(pwszPFXFile, pwszBackupDir);
  1904. wcscat(pwszPFXFile, L"\\");
  1905. wcscat(pwszPFXFile, pwszSanitizedCA);
  1906. wcscat(pwszPFXFile, wszPFXFILENAMEEXT);
  1907. DBGPRINT((DBG_SS_CERTLIBI, "myCertServerExportPFX(%ws)\n", pwszPFXFile));
  1908. hMyStore = CertOpenStore(
  1909. CERT_STORE_PROV_SYSTEM_W,
  1910. X509_ASN_ENCODING,
  1911. NULL, // hProv
  1912. CERT_STORE_OPEN_EXISTING_FLAG |
  1913. CERT_STORE_ENUM_ARCHIVED_FLAG |
  1914. CERT_SYSTEM_STORE_LOCAL_MACHINE |
  1915. CERT_STORE_READONLY_FLAG,
  1916. wszMY_CERTSTORE);
  1917. if (NULL == hMyStore)
  1918. {
  1919. hr = myHLastError();
  1920. _JumpError(hr, error, "CertOpenStore");
  1921. }
  1922. hTempMemoryStore = CertOpenStore(
  1923. CERT_STORE_PROV_MEMORY,
  1924. X509_ASN_ENCODING,
  1925. NULL,
  1926. 0,
  1927. NULL);
  1928. if (NULL == hTempMemoryStore)
  1929. {
  1930. hr = myHLastError();
  1931. _JumpError(hr, error, "CertOpenStore");
  1932. }
  1933. cCACertSaved = 0;
  1934. for (i = 0; i < cCACert; i++)
  1935. {
  1936. hr = SaveCACertChainToMemoryStore(
  1937. pwszSanitizedCA,
  1938. i,
  1939. hMyStore,
  1940. hTempMemoryStore);
  1941. _PrintIfError(hr, "SaveCACertChainToMemoryStore");
  1942. if (S_FALSE != hr)
  1943. {
  1944. _JumpIfError(hr, error, "SaveCACertChainToMemoryStore");
  1945. cCACertSaved++;
  1946. }
  1947. }
  1948. if (0 == cCACertSaved)
  1949. {
  1950. hr = CRYPT_E_NOT_FOUND;
  1951. _JumpError(hr, error, "SaveCACertChainToMemoryStore");
  1952. }
  1953. // done, have built entire chain for all CA Certs
  1954. // GemPlus returns NTE_BAD_TYPE instead of NTE_BAD_KEY, blowing up
  1955. // REPORT_NOT_ABLE* filtering. if they ever get this right, we can pass
  1956. // "[...] : EXPORT_PRIVATE_KEYS"
  1957. hr = myPFXExportCertStore(
  1958. hTempMemoryStore,
  1959. &pfx,
  1960. pwszPassword,
  1961. fMustExportPrivateKeys? (EXPORT_PRIVATE_KEYS | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY) : 0);
  1962. _JumpIfError(hr, error, "myPFXExportCertStore");
  1963. hr = EncodeToFileW(
  1964. pwszPFXFile,
  1965. pfx.pbData,
  1966. pfx.cbData,
  1967. CRYPT_STRING_BINARY | (fForceOverWrite? DECF_FORCEOVERWRITE : 0));
  1968. _JumpIfError(hr, error, "EncodeToFileW");
  1969. if (NULL != ppwszPFXFile)
  1970. {
  1971. *ppwszPFXFile = pwszPFXFile;
  1972. pwszPFXFile = NULL;
  1973. }
  1974. error:
  1975. if (NULL != pwszSanitizedCA)
  1976. {
  1977. LocalFree(pwszSanitizedCA);
  1978. }
  1979. if (NULL != pwszRevertCA)
  1980. {
  1981. LocalFree(pwszRevertCA);
  1982. }
  1983. if (NULL != pwszPFXFile)
  1984. {
  1985. LocalFree(pwszPFXFile);
  1986. }
  1987. if (NULL != hMyStore)
  1988. {
  1989. CertCloseStore(hMyStore, CERT_CLOSE_STORE_CHECK_FLAG);
  1990. }
  1991. if (NULL != hTempMemoryStore)
  1992. {
  1993. CertCloseStore(hTempMemoryStore, CERT_CLOSE_STORE_CHECK_FLAG);
  1994. }
  1995. if (NULL != pfx.pbData)
  1996. {
  1997. LocalFree(pfx.pbData);
  1998. }
  1999. if (fImpersonating)
  2000. {
  2001. myEnablePrivilege(SE_BACKUP_NAME, FALSE);
  2002. RevertToSelf();
  2003. }
  2004. return(hr);
  2005. }
  2006. HRESULT
  2007. FindKeyUsage(
  2008. IN DWORD cExtension,
  2009. IN CERT_EXTENSION const *rgExtension,
  2010. OUT DWORD *pdwUsage)
  2011. {
  2012. HRESULT hr;
  2013. DWORD i;
  2014. CRYPT_BIT_BLOB *pblob = NULL;
  2015. *pdwUsage = 0;
  2016. for (i = 0; i < cExtension; i++)
  2017. {
  2018. CERT_EXTENSION const *pce;
  2019. pce = &rgExtension[i];
  2020. if (0 == strcmp(pce->pszObjId, szOID_KEY_USAGE))
  2021. {
  2022. DWORD cb;
  2023. // Decode CRYPT_BIT_BLOB:
  2024. if (!myDecodeObject(
  2025. X509_ASN_ENCODING,
  2026. X509_KEY_USAGE,
  2027. pce->Value.pbData,
  2028. pce->Value.cbData,
  2029. CERTLIB_USE_LOCALALLOC,
  2030. (VOID **) &pblob,
  2031. &cb))
  2032. {
  2033. hr = myHLastError();
  2034. _JumpError(hr, error, "myDecodeObject");
  2035. }
  2036. if (1 > pblob->cbData || 8 < pblob->cUnusedBits)
  2037. {
  2038. hr = E_INVALIDARG;
  2039. _JumpError(hr, error, "Key Usage Extension too small");
  2040. }
  2041. *pdwUsage = *pblob->pbData;
  2042. hr = S_OK;
  2043. goto error;
  2044. }
  2045. }
  2046. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  2047. _JumpError(hr, error, "no Key Usage Extension");
  2048. error:
  2049. if (NULL != pblob)
  2050. {
  2051. LocalFree(pblob);
  2052. }
  2053. return(hr);
  2054. }
  2055. HRESULT
  2056. mySetKeySpec(
  2057. IN CERT_CONTEXT const *pCert,
  2058. OUT DWORD *pdwKeySpec)
  2059. {
  2060. HRESULT hr;
  2061. DWORD dwKeyUsage;
  2062. *pdwKeySpec = AT_SIGNATURE;
  2063. hr = FindKeyUsage(
  2064. pCert->pCertInfo->cExtension,
  2065. pCert->pCertInfo->rgExtension,
  2066. &dwKeyUsage);
  2067. _JumpIfError(hr, error, "FindKeyUsage");
  2068. if (CERT_KEY_ENCIPHERMENT_KEY_USAGE & dwKeyUsage)
  2069. {
  2070. *pdwKeySpec = AT_KEYEXCHANGE;
  2071. }
  2072. hr = S_OK;
  2073. error:
  2074. // Ignore errors because the Key Usage extension may not exist:
  2075. hr = S_OK;
  2076. return(hr);
  2077. }
  2078. HRESULT
  2079. myRepairKeyProviderInfo(
  2080. IN CERT_CONTEXT const *pCert,
  2081. IN BOOL fForceMachineKey,
  2082. IN OUT CRYPT_KEY_PROV_INFO *pkpi)
  2083. {
  2084. HRESULT hr;
  2085. BOOL fModified = FALSE;
  2086. if (0 == pkpi->dwProvType)
  2087. {
  2088. pkpi->dwProvType = PROV_RSA_FULL;
  2089. fModified = TRUE;
  2090. }
  2091. if (0 == pkpi->dwKeySpec)
  2092. {
  2093. hr = mySetKeySpec(pCert, &pkpi->dwKeySpec);
  2094. _JumpIfError(hr, error, "mySetKeySpec");
  2095. fModified = TRUE;
  2096. }
  2097. if (fForceMachineKey && 0 == (CRYPT_MACHINE_KEYSET & pkpi->dwFlags))
  2098. {
  2099. pkpi->dwFlags |= CRYPT_MACHINE_KEYSET;
  2100. fModified = TRUE;
  2101. }
  2102. if (fModified)
  2103. {
  2104. if (!CertSetCertificateContextProperty(
  2105. pCert,
  2106. CERT_KEY_PROV_INFO_PROP_ID,
  2107. 0,
  2108. pkpi))
  2109. {
  2110. hr = myHLastError();
  2111. _JumpError(hr, error, "CertSetCertificateContextProperty");
  2112. }
  2113. }
  2114. hr = S_OK;
  2115. error:
  2116. return(hr);
  2117. }
  2118. HRESULT
  2119. myRepairCertKeyProviderInfo(
  2120. IN CERT_CONTEXT const *pCert,
  2121. IN BOOL fForceMachineKey,
  2122. OPTIONAL OUT CRYPT_KEY_PROV_INFO **ppkpi)
  2123. {
  2124. HRESULT hr;
  2125. CRYPT_KEY_PROV_INFO *pkpi = NULL;
  2126. if (NULL != ppkpi)
  2127. {
  2128. *ppkpi = NULL;
  2129. }
  2130. hr = myCertGetKeyProviderInfo(pCert, &pkpi);
  2131. _JumpIfError2(hr, error, "myCertGetKeyProviderInfo", CRYPT_E_NOT_FOUND);
  2132. CSASSERT(NULL != pkpi);
  2133. hr = myRepairKeyProviderInfo(pCert, fForceMachineKey, pkpi);
  2134. _JumpIfError(hr, error, "myRepairKeyProviderInfo");
  2135. if (NULL != ppkpi)
  2136. {
  2137. *ppkpi = pkpi;
  2138. pkpi = NULL;
  2139. }
  2140. error:
  2141. if (NULL != pkpi)
  2142. {
  2143. LocalFree(pkpi);
  2144. }
  2145. return(hr);
  2146. }
  2147. HRESULT
  2148. myGetCertSubjectCommonName(
  2149. IN CERT_CONTEXT const *pCert,
  2150. OUT WCHAR **ppwszCommonName)
  2151. {
  2152. HRESULT hr;
  2153. CERT_NAME_INFO *pCertNameInfo = NULL;
  2154. DWORD cbCertNameInfo;
  2155. WCHAR const *pwszName;
  2156. if (!myDecodeName(
  2157. X509_ASN_ENCODING,
  2158. X509_UNICODE_NAME,
  2159. pCert->pCertInfo->Subject.pbData,
  2160. pCert->pCertInfo->Subject.cbData,
  2161. CERTLIB_USE_LOCALALLOC,
  2162. &pCertNameInfo,
  2163. &cbCertNameInfo))
  2164. {
  2165. hr = myHLastError();
  2166. _JumpError(hr, error, "myDecodeName");
  2167. }
  2168. hr = myGetCertNameProperty(pCertNameInfo, szOID_COMMON_NAME, &pwszName);
  2169. _JumpIfError(hr, error, "myGetCertNameProperty");
  2170. *ppwszCommonName = (WCHAR *) LocalAlloc(
  2171. LMEM_FIXED,
  2172. (wcslen(pwszName) + 1) * sizeof(WCHAR));
  2173. if (NULL == *ppwszCommonName)
  2174. {
  2175. hr = E_OUTOFMEMORY;
  2176. _JumpError(hr, error, "LocalAlloc");
  2177. }
  2178. wcscpy(*ppwszCommonName, pwszName);
  2179. hr = S_OK;
  2180. error:
  2181. if (NULL != pCertNameInfo)
  2182. {
  2183. LocalFree(pCertNameInfo);
  2184. }
  2185. return(hr);
  2186. }
  2187. HRESULT
  2188. myGetChainArrayFromStore(
  2189. IN HCERTSTORE hStore,
  2190. IN BOOL fCAChain,
  2191. IN BOOL fUserStore,
  2192. OPTIONAL OUT WCHAR **ppwszCommonName,
  2193. IN OUT DWORD *pcRestoreChain,
  2194. OPTIONAL OUT RESTORECHAIN *paRestoreChain)
  2195. {
  2196. HRESULT hr;
  2197. CERT_CONTEXT const *pCert = NULL;
  2198. WCHAR *pwszCommonName = NULL;
  2199. CERT_CHAIN_PARA ChainParams;
  2200. CRYPT_KEY_PROV_INFO *pkpi = NULL;
  2201. DWORD iRestoreChain = 0;
  2202. if (NULL != ppwszCommonName)
  2203. {
  2204. *ppwszCommonName = NULL;
  2205. }
  2206. if (NULL != paRestoreChain)
  2207. {
  2208. ZeroMemory(paRestoreChain, *pcRestoreChain * sizeof(paRestoreChain[0]));
  2209. }
  2210. // Look for certificates with keys. There should be at least one.
  2211. while (TRUE)
  2212. {
  2213. BOOL fMatchingKey;
  2214. WCHAR *pwszCommonNameT;
  2215. CERT_CHAIN_CONTEXT const *pChain;
  2216. DWORD NameId;
  2217. pCert = CertEnumCertificatesInStore(hStore, pCert);
  2218. if (NULL == pCert)
  2219. {
  2220. break;
  2221. }
  2222. if (NULL != pkpi)
  2223. {
  2224. LocalFree(pkpi);
  2225. pkpi = NULL;
  2226. }
  2227. hr = myRepairCertKeyProviderInfo(pCert, !fUserStore, &pkpi);
  2228. if (S_OK != hr)
  2229. {
  2230. if (CRYPT_E_NOT_FOUND == hr)
  2231. {
  2232. continue;
  2233. }
  2234. _JumpError(hr, error, "myRepairCertKeyProviderInfo");
  2235. }
  2236. if (NULL == pkpi || NULL == pkpi->pwszContainerName)
  2237. {
  2238. continue;
  2239. }
  2240. hr = myVerifyPublicKey(
  2241. pCert,
  2242. FALSE,
  2243. pkpi, // pKeyProvInfo
  2244. NULL, // pPublicKeyInfo
  2245. &fMatchingKey);
  2246. _JumpIfError(hr, error, "myVerifyPublicKey");
  2247. if (!fMatchingKey)
  2248. {
  2249. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2250. _JumpError(hr, error, "Key doesn't match cert");
  2251. }
  2252. hr = myGetCertSubjectCommonName(pCert, &pwszCommonNameT);
  2253. _JumpIfError(hr, error, "myGetCertSubjectCommonName");
  2254. if (NULL == pwszCommonName)
  2255. {
  2256. pwszCommonName = pwszCommonNameT;
  2257. }
  2258. else
  2259. {
  2260. if (0 != lstrcmp(pwszCommonName, pwszCommonNameT))
  2261. {
  2262. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2263. _JumpError(hr, error, "multiple CommonNames");
  2264. }
  2265. LocalFree(pwszCommonNameT);
  2266. }
  2267. if (fCAChain)
  2268. {
  2269. hr = myGetNameId(pCert, &NameId);
  2270. _PrintIfError(hr, "myGetNameId");
  2271. }
  2272. else
  2273. {
  2274. NameId = 0;
  2275. }
  2276. if (NULL != paRestoreChain && iRestoreChain >= *pcRestoreChain)
  2277. {
  2278. hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
  2279. _JumpError(hr, error, "Chain array full");
  2280. }
  2281. ZeroMemory(&ChainParams, sizeof(ChainParams));
  2282. ChainParams.cbSize = sizeof(ChainParams);
  2283. ChainParams.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
  2284. // Get the chain and verify the cert:
  2285. if (!CertGetCertificateChain(
  2286. HCCE_LOCAL_MACHINE, // hChainEngine
  2287. pCert, // pCertContext
  2288. NULL, // pTime
  2289. hStore, // hAdditionalStore
  2290. &ChainParams, // pChainPara
  2291. 0, // dwFlags
  2292. NULL, // pvReserved
  2293. &pChain)) // ppChainContext
  2294. {
  2295. hr = myHLastError();
  2296. _JumpIfError(hr, error, "CertGetCertificateChain");
  2297. }
  2298. if (NULL != paRestoreChain)
  2299. {
  2300. paRestoreChain[iRestoreChain].pChain = pChain;
  2301. paRestoreChain[iRestoreChain].NameId = NameId;
  2302. }
  2303. else
  2304. {
  2305. CertFreeCertificateChain(pChain);
  2306. }
  2307. iRestoreChain++;
  2308. }
  2309. if (NULL != ppwszCommonName)
  2310. {
  2311. *ppwszCommonName = pwszCommonName;
  2312. pwszCommonName = NULL;
  2313. }
  2314. *pcRestoreChain = iRestoreChain;
  2315. hr = S_OK;
  2316. error:
  2317. if (S_OK != hr && NULL != paRestoreChain)
  2318. {
  2319. for (iRestoreChain = 0; iRestoreChain < *pcRestoreChain; iRestoreChain++)
  2320. {
  2321. if (NULL != paRestoreChain[iRestoreChain].pChain)
  2322. {
  2323. CertFreeCertificateChain(paRestoreChain[iRestoreChain].pChain);
  2324. paRestoreChain[iRestoreChain].pChain = NULL;
  2325. }
  2326. }
  2327. }
  2328. if (NULL != pwszCommonName)
  2329. {
  2330. LocalFree(pwszCommonName);
  2331. }
  2332. if (NULL != pkpi)
  2333. {
  2334. LocalFree(pkpi);
  2335. }
  2336. if (NULL != pCert)
  2337. {
  2338. CertFreeCertificateContext(pCert);
  2339. }
  2340. return(hr);
  2341. }
  2342. HRESULT
  2343. myCopyKeys(
  2344. IN CRYPT_KEY_PROV_INFO const *pkpi,
  2345. IN WCHAR const *pwszOldContainer,
  2346. IN WCHAR const *pwszNewContainer,
  2347. IN BOOL fOldUserKey,
  2348. IN BOOL fNewUserKey,
  2349. IN BOOL fForceOverWrite)
  2350. {
  2351. HRESULT hr;
  2352. HCRYPTPROV hProvOld = NULL;
  2353. HCRYPTKEY hKeyOld = NULL;
  2354. HCRYPTPROV hProvNew = NULL;
  2355. HCRYPTKEY hKeyNew = NULL;
  2356. CRYPT_BIT_BLOB PrivateKey;
  2357. BOOL fKeyContainerNotFound = FALSE;
  2358. PrivateKey.pbData = NULL;
  2359. if (!myCertSrvCryptAcquireContext(
  2360. &hProvOld,
  2361. pwszOldContainer,
  2362. pkpi->pwszProvName,
  2363. pkpi->dwProvType,
  2364. pkpi->dwFlags,
  2365. !fOldUserKey))
  2366. {
  2367. hr = myHLastError();
  2368. _JumpError(hr, error, "myCertSrvCryptAcquireContext");
  2369. }
  2370. if (!CryptGetUserKey(hProvOld, pkpi->dwKeySpec, &hKeyOld))
  2371. {
  2372. hr = myHLastError();
  2373. _JumpError(hr, error, "CryptGetUserKey");
  2374. }
  2375. hr = myCryptExportPrivateKey(
  2376. hKeyOld,
  2377. &PrivateKey.pbData,
  2378. &PrivateKey.cbData);
  2379. _JumpIfError(hr, error, "myCryptExportPrivateKey");
  2380. if (myCertSrvCryptAcquireContext(
  2381. &hProvNew,
  2382. pwszNewContainer,
  2383. pkpi->pwszProvName,
  2384. pkpi->dwProvType,
  2385. pkpi->dwFlags,
  2386. !fNewUserKey))
  2387. {
  2388. if (!fForceOverWrite)
  2389. {
  2390. hr = HRESULT_FROM_WIN32(ERROR_FILE_EXISTS);
  2391. _JumpErrorStr(hr, error, "Key Container Exists", pwszNewContainer);
  2392. }
  2393. // Delete the target key container
  2394. CryptReleaseContext(hProvNew, 0);
  2395. if (myCertSrvCryptAcquireContext(
  2396. &hProvNew,
  2397. pwszNewContainer,
  2398. pkpi->pwszProvName,
  2399. pkpi->dwProvType,
  2400. pkpi->dwFlags | CRYPT_DELETEKEYSET,
  2401. !fNewUserKey))
  2402. {
  2403. fKeyContainerNotFound = TRUE;
  2404. }
  2405. hProvNew = NULL;
  2406. }
  2407. else
  2408. {
  2409. fKeyContainerNotFound = TRUE;
  2410. }
  2411. if (!myCertSrvCryptAcquireContext(
  2412. &hProvNew,
  2413. pwszNewContainer,
  2414. pkpi->pwszProvName,
  2415. pkpi->dwProvType,
  2416. pkpi->dwFlags |
  2417. fKeyContainerNotFound? CRYPT_NEWKEYSET : 0,
  2418. !fNewUserKey))
  2419. {
  2420. hr = myHLastError();
  2421. _JumpError(hr, error, "myCertSrvCryptAcquireContext");
  2422. }
  2423. if (!CryptImportKey(
  2424. hProvNew,
  2425. PrivateKey.pbData,
  2426. PrivateKey.cbData,
  2427. NULL, // HCRYPTKEY hPubKey
  2428. CRYPT_EXPORTABLE,
  2429. &hKeyNew))
  2430. {
  2431. hr = myHLastError();
  2432. _JumpError(hr, error, "CryptImportKey");
  2433. }
  2434. error:
  2435. if (NULL != PrivateKey.pbData)
  2436. {
  2437. LocalFree(PrivateKey.pbData);
  2438. }
  2439. if (NULL != hKeyNew)
  2440. {
  2441. CryptDestroyKey(hKeyNew);
  2442. }
  2443. if (NULL != hProvNew)
  2444. {
  2445. CryptReleaseContext(hProvNew, 0);
  2446. }
  2447. if (NULL != hKeyOld)
  2448. {
  2449. CryptDestroyKey(hKeyOld);
  2450. }
  2451. if (NULL != hProvOld)
  2452. {
  2453. CryptReleaseContext(hProvOld, 0);
  2454. }
  2455. return(hr);
  2456. }
  2457. HRESULT
  2458. myImportChainAndKeys(
  2459. IN WCHAR const *pwszSanitizedCA,
  2460. IN DWORD iCert,
  2461. IN DWORD iKey,
  2462. IN BOOL fForceOverWrite,
  2463. IN CERT_CHAIN_CONTEXT const *pChain,
  2464. OPTIONAL OUT CERT_CONTEXT const **ppccNewestCA)
  2465. {
  2466. HRESULT hr;
  2467. BOOL fDeleted = FALSE;
  2468. CRYPT_KEY_PROV_INFO *pkpi = NULL;
  2469. CERT_CHAIN_ELEMENT **ppChainElement;
  2470. WCHAR *pwszKeyContainerName = NULL;
  2471. hr = myAllocIndexedName(pwszSanitizedCA, iKey, &pwszKeyContainerName);
  2472. _JumpIfError(hr, error, "myAllocIndexedName");
  2473. ppChainElement = pChain->rgpChain[0]->rgpElement;
  2474. hr = myCertGetKeyProviderInfo(ppChainElement[0]->pCertContext, &pkpi);
  2475. _JumpIfError(hr, error, "myCertGetKeyProviderInfo");
  2476. if (iCert == iKey)
  2477. {
  2478. hr = myCopyKeys(
  2479. pkpi,
  2480. pkpi->pwszContainerName, // pwszOldContainer
  2481. pwszKeyContainerName, // pwszNewContainer
  2482. FALSE, // fOldUserKey
  2483. FALSE, // fNewUserKey
  2484. fForceOverWrite);
  2485. _JumpIfError(hr, error, "myCopyKeys");
  2486. }
  2487. pkpi->pwszContainerName = pwszKeyContainerName;
  2488. hr = mySaveChainAndKeys(
  2489. pChain->rgpChain[0],
  2490. wszMY_CERTSTORE,
  2491. CERT_SYSTEM_STORE_LOCAL_MACHINE |
  2492. CERT_STORE_BACKUP_RESTORE_FLAG,
  2493. pkpi,
  2494. ppccNewestCA);
  2495. _JumpIfError(hr, error, "mySaveChainAndKeys");
  2496. hr = S_OK;
  2497. error:
  2498. if (NULL != pkpi)
  2499. {
  2500. LocalFree(pkpi);
  2501. }
  2502. if (NULL != pwszKeyContainerName)
  2503. {
  2504. LocalFree(pwszKeyContainerName);
  2505. }
  2506. return(hr);
  2507. }
  2508. HRESULT
  2509. FindPFXInBackupDir(
  2510. IN WCHAR const *pwszBackupDir,
  2511. OUT WCHAR **ppwszPFXFile)
  2512. {
  2513. HRESULT hr;
  2514. HANDLE hf;
  2515. WIN32_FIND_DATA wfd;
  2516. WCHAR wszpath[MAX_PATH];
  2517. WCHAR wszfile[MAX_PATH];
  2518. DWORD cFile = 0;
  2519. *ppwszPFXFile = NULL;
  2520. wcscpy(wszpath, pwszBackupDir);
  2521. wcscat(wszpath, L"\\*");
  2522. wcscat(wszpath, wszPFXFILENAMEEXT);
  2523. hf = FindFirstFile(wszpath, &wfd);
  2524. if (INVALID_HANDLE_VALUE != hf)
  2525. {
  2526. do {
  2527. if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  2528. {
  2529. continue;
  2530. }
  2531. cFile++;
  2532. wcscpy(wszfile, wfd.cFileName);
  2533. //printf("File: %ws\n", wszfile);
  2534. break;
  2535. } while (FindNextFile(hf, &wfd));
  2536. FindClose(hf);
  2537. }
  2538. if (0 == cFile)
  2539. {
  2540. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  2541. _JumpError(hr, error, "no *.p12 files");
  2542. }
  2543. if (1 < cFile)
  2544. {
  2545. hr = HRESULT_FROM_WIN32(ERROR_DIRECTORY);
  2546. _JumpError(hr, error, "Too many *.p12 files");
  2547. }
  2548. *ppwszPFXFile = (WCHAR *) LocalAlloc(
  2549. LMEM_FIXED,
  2550. (wcslen(pwszBackupDir) +
  2551. 1 +
  2552. wcslen(wszfile) +
  2553. 1) * sizeof(WCHAR));
  2554. if (NULL == *ppwszPFXFile)
  2555. {
  2556. hr = E_OUTOFMEMORY;
  2557. _JumpError(hr, error, "LocalAlloc");
  2558. }
  2559. wcscpy(*ppwszPFXFile, pwszBackupDir);
  2560. wcscat(*ppwszPFXFile, L"\\");
  2561. wcscat(*ppwszPFXFile, wszfile);
  2562. hr = S_OK;
  2563. error:
  2564. return(hr);
  2565. }
  2566. // Return TRUE if pcc is newer than pcc2
  2567. BOOL
  2568. IsCACertNewer(
  2569. IN CERT_CONTEXT const *pcc,
  2570. IN DWORD NameId,
  2571. IN CERT_CONTEXT const *pcc2,
  2572. IN DWORD NameId2)
  2573. {
  2574. BOOL fNewer = FALSE;
  2575. CERT_INFO const *pci = pcc->pCertInfo;
  2576. CERT_INFO const *pci2 = pcc2->pCertInfo;
  2577. if (MAXDWORD != NameId && MAXDWORD != NameId2)
  2578. {
  2579. if (CANAMEIDTOICERT(NameId) > CANAMEIDTOICERT(NameId2))
  2580. {
  2581. fNewer = TRUE;
  2582. }
  2583. }
  2584. else
  2585. if (CompareFileTime(&pci->NotAfter, &pci2->NotAfter) > 0)
  2586. {
  2587. fNewer = TRUE;
  2588. }
  2589. #if 0
  2590. HRESULT hr;
  2591. WCHAR *pwszDate = NULL;
  2592. WCHAR *pwszDate2 = NULL;
  2593. hr = myGMTFileTimeToWszLocalTime(&pci->NotAfter, &pwszDate);
  2594. _PrintIfError(hr, "myGMTFileTimeToWszLocalTime");
  2595. hr = myGMTFileTimeToWszLocalTime(&pci2->NotAfter, &pwszDate2);
  2596. _PrintIfError(hr, "myGMTFileTimeToWszLocalTime");
  2597. printf(
  2598. "%u.%u %ws is %wsnewer than %u.%u %ws\n",
  2599. CANAMEIDTOICERT(NameId),
  2600. CANAMEIDTOIKEY(NameId),
  2601. pwszDate,
  2602. fNewer? L"" : L"NOT ",
  2603. CANAMEIDTOICERT(NameId2),
  2604. CANAMEIDTOIKEY(NameId2),
  2605. pwszDate2);
  2606. if (NULL != pwszDate) LocalFree(pwszDate);
  2607. if (NULL != pwszDate2) LocalFree(pwszDate2);
  2608. #endif
  2609. return(fNewer);
  2610. }
  2611. #if 0
  2612. VOID
  2613. DumpChainArray(
  2614. IN char const *psz,
  2615. IN DWORD cCACert,
  2616. IN OUT RESTORECHAIN *paRestoreChain)
  2617. {
  2618. HRESULT hr;
  2619. DWORD i;
  2620. printf("\n%hs:\n", psz);
  2621. for (i = 0; i < cCACert; i++)
  2622. {
  2623. WCHAR *pwszDate;
  2624. hr = myGMTFileTimeToWszLocalTime(
  2625. &paRestoreChain[i].pChain->rgpChain[0]->rgpElement[0]->pCertContext->pCertInfo->NotBefore,
  2626. &pwszDate);
  2627. _PrintIfError(hr, "myGMTFileTimeToWszLocalTime");
  2628. printf(
  2629. " %u: %u.%u %ws",
  2630. i,
  2631. CANAMEIDTOICERT(paRestoreChain[i].NameId),
  2632. CANAMEIDTOIKEY(paRestoreChain[i].NameId),
  2633. pwszDate);
  2634. if (NULL != pwszDate) LocalFree(pwszDate);
  2635. hr = myGMTFileTimeToWszLocalTime(
  2636. &paRestoreChain[i].pChain->rgpChain[0]->rgpElement[0]->pCertContext->pCertInfo->NotAfter,
  2637. &pwszDate);
  2638. _PrintIfError(hr, "myGMTFileTimeToWszLocalTime");
  2639. printf(" -- %ws\n", pwszDate);
  2640. if (NULL != pwszDate) LocalFree(pwszDate);
  2641. }
  2642. printf("\n");
  2643. }
  2644. #endif
  2645. HRESULT
  2646. SortCACerts(
  2647. IN DWORD cCACert,
  2648. IN OUT RESTORECHAIN *paRestoreChain)
  2649. {
  2650. HRESULT hr;
  2651. DWORD i;
  2652. DWORD j;
  2653. #if 0
  2654. DumpChainArray("Start", cCACert, paRestoreChain);
  2655. #endif
  2656. for (i = 0; i < cCACert; i++)
  2657. {
  2658. for (j = i + 1; j < cCACert; j++)
  2659. {
  2660. CERT_CHAIN_CONTEXT const *pChain;
  2661. DWORD NameId;
  2662. DWORD NameId2;
  2663. CERT_CONTEXT const *pcc;
  2664. CERT_CONTEXT const *pcc2;
  2665. pChain = paRestoreChain[i].pChain;
  2666. NameId = paRestoreChain[i].NameId;
  2667. NameId2 = paRestoreChain[j].NameId;
  2668. pcc = pChain->rgpChain[0]->rgpElement[0]->pCertContext;
  2669. pcc2 = paRestoreChain[j].pChain->rgpChain[0]->rgpElement[0]->pCertContext;
  2670. #if 0
  2671. printf(
  2672. "%u(%u.%u) %u(%u.%u): ",
  2673. i,
  2674. CANAMEIDTOIKEY(NameId),
  2675. CANAMEIDTOICERT(NameId),
  2676. j,
  2677. CANAMEIDTOIKEY(NameId2),
  2678. CANAMEIDTOICERT(NameId2));
  2679. #endif
  2680. if (IsCACertNewer(pcc, NameId, pcc2, NameId2))
  2681. {
  2682. paRestoreChain[i] = paRestoreChain[j];
  2683. paRestoreChain[j].pChain = pChain;
  2684. paRestoreChain[j].NameId = NameId;
  2685. }
  2686. }
  2687. }
  2688. #if 0
  2689. DumpChainArray("End", cCACert, paRestoreChain);
  2690. #endif
  2691. hr = S_OK;
  2692. //error:
  2693. return(hr);
  2694. }
  2695. HRESULT
  2696. myDeleteGuidKeys(
  2697. IN HCERTSTORE hStorePFX,
  2698. IN BOOL fMachineKeySet)
  2699. {
  2700. HRESULT hr;
  2701. CERT_CONTEXT const *pCert = NULL;
  2702. CRYPT_KEY_PROV_INFO *pkpi = NULL;
  2703. // Look for certificates with keys, and delete all key containers with
  2704. // names that look like GUIDs.
  2705. while (TRUE)
  2706. {
  2707. HCRYPTPROV hProv;
  2708. pCert = CertEnumCertificatesInStore(hStorePFX, pCert);
  2709. if (NULL == pCert)
  2710. {
  2711. break;
  2712. }
  2713. if (NULL != pkpi)
  2714. {
  2715. LocalFree(pkpi);
  2716. pkpi = NULL;
  2717. }
  2718. hr = myRepairCertKeyProviderInfo(pCert, FALSE, &pkpi);
  2719. if (S_OK == hr &&
  2720. NULL != pkpi->pwszContainerName &&
  2721. wcLBRACE == *pkpi->pwszContainerName)
  2722. {
  2723. if (myCertSrvCryptAcquireContext(
  2724. &hProv,
  2725. pkpi->pwszContainerName,
  2726. pkpi->pwszProvName,
  2727. pkpi->dwProvType,
  2728. pkpi->dwFlags | CRYPT_DELETEKEYSET,
  2729. fMachineKeySet))
  2730. {
  2731. DBGPRINT((
  2732. DBG_SS_CERTLIBI,
  2733. "myDeleteGuidKeys(%ws, %ws)\n",
  2734. fMachineKeySet? L"Machine" : L"User",
  2735. pkpi->pwszContainerName));
  2736. }
  2737. }
  2738. }
  2739. hr = S_OK;
  2740. //error:
  2741. if (NULL != pkpi)
  2742. {
  2743. LocalFree(pkpi);
  2744. }
  2745. if (NULL != pCert)
  2746. {
  2747. CertFreeCertificateContext(pCert);
  2748. }
  2749. return(hr);
  2750. }
  2751. HRESULT
  2752. myCertServerImportPFX(
  2753. IN WCHAR const *pwszBackupDirOrPFXFile,
  2754. IN WCHAR const *pwszPassword,
  2755. IN BOOL fForceOverWrite,
  2756. OPTIONAL OUT WCHAR **ppwszCommonName,
  2757. OPTIONAL OUT WCHAR **ppwszPFXFile,
  2758. OPTIONAL OUT CERT_CONTEXT const **ppccNewestCA)
  2759. {
  2760. HRESULT hr;
  2761. CRYPT_DATA_BLOB pfx;
  2762. HCERTSTORE hStorePFX = NULL;
  2763. WCHAR *pwszCommonName = NULL;
  2764. WCHAR *pwszSanitizedName = NULL;
  2765. RESTORECHAIN *paRestoreChain = NULL;
  2766. WCHAR *pwszPFXFile = NULL;
  2767. DWORD FileAttr;
  2768. BOOL fImpersonating = FALSE;
  2769. DWORD cCACert;
  2770. DWORD iCert;
  2771. pfx.pbData = NULL;
  2772. if (NULL != ppwszCommonName)
  2773. {
  2774. *ppwszCommonName = NULL;
  2775. }
  2776. if (NULL != ppwszPFXFile)
  2777. {
  2778. *ppwszPFXFile = NULL;
  2779. }
  2780. if (NULL != ppccNewestCA)
  2781. {
  2782. *ppccNewestCA = NULL;
  2783. }
  2784. if (!ImpersonateSelf(SecurityImpersonation))
  2785. {
  2786. hr = myHLastError();
  2787. _JumpError(hr, error, "ImpersonateSelf");
  2788. }
  2789. fImpersonating = TRUE;
  2790. hr = myEnablePrivilege(SE_RESTORE_NAME, TRUE);
  2791. _JumpIfError(hr, error, "myEnablePrivilege");
  2792. hr = myEnablePrivilege(SE_BACKUP_NAME, TRUE);
  2793. _JumpIfError(hr, error, "myEnablePrivilege");
  2794. FileAttr = GetFileAttributes(pwszBackupDirOrPFXFile);
  2795. if (MAXDWORD == FileAttr)
  2796. {
  2797. hr = myHLastError();
  2798. _JumpError(hr, error, "GetFileAttributes");
  2799. }
  2800. if (FILE_ATTRIBUTE_DIRECTORY & FileAttr)
  2801. {
  2802. hr = FindPFXInBackupDir(pwszBackupDirOrPFXFile, &pwszPFXFile);
  2803. _JumpIfError(hr, error, "FindPFXInBackupDir");
  2804. }
  2805. else
  2806. {
  2807. hr = myDupString(pwszBackupDirOrPFXFile, &pwszPFXFile);
  2808. _JumpIfError(hr, error, "myDupString");
  2809. }
  2810. hr = DecodeFileW(pwszPFXFile, &pfx.pbData, &pfx.cbData, CRYPT_STRING_ANY);
  2811. _JumpIfError(hr, error, "DecodeFileW");
  2812. CSASSERT(NULL != pfx.pbData);
  2813. if (!PFXIsPFXBlob(&pfx))
  2814. {
  2815. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2816. _JumpError(hr, error, "PFXIsPFXBlob");
  2817. }
  2818. hStorePFX = myPFXImportCertStore(&pfx, pwszPassword, CRYPT_EXPORTABLE);
  2819. if (NULL == hStorePFX)
  2820. {
  2821. hr = myHLastError();
  2822. _JumpError(hr, error, "myPFXImportCertStore");
  2823. }
  2824. cCACert = 0;
  2825. hr = myGetChainArrayFromStore(
  2826. hStorePFX,
  2827. TRUE, // fCAChain
  2828. FALSE, // fUserStore
  2829. &pwszCommonName,
  2830. &cCACert,
  2831. NULL);
  2832. _JumpIfError(hr, error, "myGetChainArrayFromStore");
  2833. if (0 == cCACert)
  2834. {
  2835. hr = HRESULT_FROM_WIN32(CRYPT_E_SELF_SIGNED);
  2836. _JumpError(hr, error, "myGetChainArrayFromStore <no chain>");
  2837. }
  2838. paRestoreChain = (RESTORECHAIN *) LocalAlloc(
  2839. LMEM_FIXED | LMEM_ZEROINIT,
  2840. cCACert * sizeof(paRestoreChain[0]));
  2841. if (NULL == paRestoreChain)
  2842. {
  2843. hr = E_OUTOFMEMORY;
  2844. _JumpError(hr, error, "LocalAlloc");
  2845. }
  2846. hr = myGetChainArrayFromStore(
  2847. hStorePFX,
  2848. TRUE, // fCAChain
  2849. FALSE, // fUserStore
  2850. NULL,
  2851. &cCACert,
  2852. paRestoreChain);
  2853. _JumpIfError(hr, error, "myGetChainArrayFromStore");
  2854. hr = SortCACerts(cCACert, paRestoreChain);
  2855. _JumpIfError(hr, error, "SortCACerts");
  2856. hr = mySanitizeName(pwszCommonName, &pwszSanitizedName);
  2857. _JumpIfError(hr, error, "mySanitizeName");
  2858. for (iCert = 0; iCert < cCACert; iCert++)
  2859. {
  2860. CERT_CHAIN_CONTEXT const *pChain = paRestoreChain[iCert].pChain;
  2861. DWORD iKey;
  2862. CERT_PUBLIC_KEY_INFO *pPublicKeyInfo;
  2863. if (1 > pChain->cChain)
  2864. {
  2865. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2866. _JumpError(hr, error, "No Chain Context");
  2867. }
  2868. // Compute iKey by comparing this public key to the public keys
  2869. // of all certs in the array already processed.
  2870. pPublicKeyInfo = &pChain->rgpChain[0]->rgpElement[0]->pCertContext->pCertInfo->SubjectPublicKeyInfo;
  2871. for (iKey = 0; iKey < iCert; iKey++)
  2872. {
  2873. if (CertComparePublicKeyInfo(
  2874. X509_ASN_ENCODING,
  2875. pPublicKeyInfo,
  2876. &paRestoreChain[iKey].pChain->rgpChain[0]->rgpElement[0]->pCertContext->pCertInfo->SubjectPublicKeyInfo))
  2877. {
  2878. // by design, CertComparePublicKeyInfo doesn't set last error!
  2879. break;
  2880. }
  2881. }
  2882. DBGPRINT((
  2883. DBG_SS_CERTLIB,
  2884. "Import: %u.%u -- %u.%u\n",
  2885. iCert,
  2886. iKey,
  2887. CANAMEIDTOICERT(paRestoreChain[iCert].NameId),
  2888. CANAMEIDTOIKEY(paRestoreChain[iCert].NameId)));
  2889. // Retrieve the cert context for the newest CA cert chain in the PFX
  2890. // we are importing. We must return a cert context with the new
  2891. // key prov info, not the PFX cert context with a GUID key container.
  2892. hr = myImportChainAndKeys(
  2893. pwszSanitizedName,
  2894. iCert,
  2895. iKey,
  2896. fForceOverWrite,
  2897. pChain,
  2898. iCert + 1 == cCACert? ppccNewestCA : NULL);
  2899. _JumpIfError(hr, error, "myImportChainAndKeys");
  2900. }
  2901. if (NULL != ppwszCommonName)
  2902. {
  2903. *ppwszCommonName = pwszCommonName;
  2904. pwszCommonName = NULL;
  2905. }
  2906. if (NULL != ppwszPFXFile)
  2907. {
  2908. *ppwszPFXFile = pwszPFXFile;
  2909. pwszPFXFile = NULL;
  2910. }
  2911. hr = S_OK;
  2912. error:
  2913. if (NULL != paRestoreChain)
  2914. {
  2915. for (iCert = 0; iCert < cCACert; iCert++)
  2916. {
  2917. if (NULL != paRestoreChain[iCert].pChain)
  2918. {
  2919. CertFreeCertificateChain(paRestoreChain[iCert].pChain);
  2920. }
  2921. }
  2922. LocalFree(paRestoreChain);
  2923. }
  2924. if (NULL != pwszPFXFile)
  2925. {
  2926. LocalFree(pwszPFXFile);
  2927. }
  2928. if (NULL != pwszCommonName)
  2929. {
  2930. LocalFree(pwszCommonName);
  2931. }
  2932. if (NULL != pwszSanitizedName)
  2933. {
  2934. LocalFree(pwszSanitizedName);
  2935. }
  2936. if (NULL != hStorePFX)
  2937. {
  2938. myDeleteGuidKeys(hStorePFX, TRUE);
  2939. CertCloseStore(hStorePFX, CERT_CLOSE_STORE_CHECK_FLAG);
  2940. }
  2941. if (NULL != pfx.pbData)
  2942. {
  2943. LocalFree(pfx.pbData);
  2944. }
  2945. if (fImpersonating)
  2946. {
  2947. myEnablePrivilege(SE_RESTORE_NAME, FALSE);
  2948. myEnablePrivilege(SE_BACKUP_NAME, FALSE);
  2949. RevertToSelf();
  2950. }
  2951. return(hr);
  2952. }