Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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