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.

1184 lines
36 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows NT Security
  4. // Copyright (C) Microsoft Corporation, 1997 - 1999
  5. //
  6. // File: scheme.cpp
  7. //
  8. // Contents: Generic Scheme Provider Utility Functions
  9. //
  10. // History: 18-Aug-97 kirtd Created
  11. // 01-Jan-02 philh Moved from wininet to winhttp
  12. //
  13. //----------------------------------------------------------------------------
  14. #include <global.hxx>
  15. #include <userenv.h>
  16. #include <userenvp.h> // for GetUserAppDataPathW
  17. #include <dbgdef.h>
  18. //+-------------------------------------------------------------------------
  19. // For impersonation, return thread token, otherwise, return process token
  20. //--------------------------------------------------------------------------
  21. HANDLE
  22. WINAPI
  23. I_SchemeGetToken()
  24. {
  25. HANDLE hToken = NULL;
  26. DWORD dwErr;
  27. //
  28. // first, attempt to look at the thread token. If none exists,
  29. // which is true if the thread is not impersonating, try the
  30. // process token.
  31. //
  32. if (!OpenThreadToken(
  33. GetCurrentThread(),
  34. TOKEN_QUERY | TOKEN_IMPERSONATE,
  35. TRUE,
  36. &hToken
  37. )) {
  38. dwErr = GetLastError();
  39. if (ERROR_NO_TOKEN != dwErr)
  40. goto OpenThreadTokenError;
  41. if (!OpenProcessToken(GetCurrentProcess(),
  42. TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &hToken)) {
  43. dwErr = GetLastError();
  44. goto OpenProcessTokenError;
  45. }
  46. }
  47. CommonReturn:
  48. return hToken;
  49. ErrorReturn:
  50. hToken = NULL;
  51. goto CommonReturn;
  52. SET_ERROR_VAR(OpenThreadTokenError, dwErr)
  53. SET_ERROR_VAR(OpenProcessTokenError, dwErr)
  54. }
  55. //+-------------------------------------------------------------------------
  56. // Ensure LastError is preserved
  57. //--------------------------------------------------------------------------
  58. VOID
  59. WINAPI
  60. I_SchemeCloseHandle(
  61. IN HANDLE h
  62. )
  63. {
  64. if (h) {
  65. DWORD dwErr = GetLastError();
  66. CloseHandle(h);
  67. SetLastError(dwErr);
  68. }
  69. }
  70. //+-------------------------------------------------------------------------
  71. // Returns %UserProfile%\Microsoft\CryptnetUrlCache\ which must be
  72. // freed via PkiFree().
  73. //--------------------------------------------------------------------------
  74. LPWSTR
  75. WINAPI
  76. I_SchemeGetCryptnetUrlCacheDir()
  77. {
  78. DWORD dwErr;
  79. HANDLE hToken = NULL;
  80. LPWSTR pwszDir = NULL;
  81. DWORD cchDir;
  82. WCHAR wszAppDataPath[MAX_PATH + 1];
  83. hToken = I_SchemeGetToken();
  84. wszAppDataPath[0] = L'\0';
  85. dwErr = GetUserAppDataPathW(
  86. hToken,
  87. FALSE, // fLocalAppData
  88. wszAppDataPath
  89. );
  90. if (ERROR_SUCCESS != dwErr || L'\0' == wszAppDataPath[0])
  91. goto GetUserAppDataPathError;
  92. wszAppDataPath[MAX_PATH] = L'\0';
  93. #if DBG
  94. DbgPrintf(DBG_SS_CRYPT32, "userenv!GetUserAppDataPathW:: %S\n",
  95. wszAppDataPath);
  96. #endif
  97. cchDir = wcslen(wszAppDataPath) + wcslen(SCHEME_CRYPTNET_URL_CACHE_DIR) + 1;
  98. pwszDir = (LPWSTR) PkiNonzeroAlloc(cchDir * sizeof(WCHAR));
  99. if (NULL == pwszDir)
  100. goto OutOfMemory;
  101. wcscpy(pwszDir, wszAppDataPath);
  102. wcscat(pwszDir, SCHEME_CRYPTNET_URL_CACHE_DIR);
  103. CommonReturn:
  104. if (hToken)
  105. I_SchemeCloseHandle(hToken);
  106. return pwszDir;
  107. ErrorReturn:
  108. pwszDir = NULL;
  109. goto CommonReturn;
  110. SET_ERROR_VAR(GetUserAppDataPathError, dwErr)
  111. TRACE_ERROR(OutOfMemory)
  112. }
  113. //+-------------------------------------------------------------------------
  114. // Converts the bytes into UNICODE HEX
  115. //
  116. // Needs (cb * 2 + 1) * sizeof(WCHAR) bytes of space in wsz
  117. //--------------------------------------------------------------------------
  118. VOID
  119. WINAPI
  120. I_SchemeBytesToWStr(DWORD cb, void* pv, LPWSTR wsz)
  121. {
  122. BYTE* pb = (BYTE*) pv;
  123. for (DWORD i = 0; i<cb; i++) {
  124. int b;
  125. b = (*pb & 0xF0) >> 4;
  126. *wsz++ = (WCHAR)( (b <= 9) ? b + L'0' : (b - 10) + L'A');
  127. b = *pb & 0x0F;
  128. *wsz++ = (WCHAR)( (b <= 9) ? b + L'0' : (b - 10) + L'A');
  129. pb++;
  130. }
  131. *wsz++ = 0;
  132. }
  133. //+-------------------------------------------------------------------------
  134. // Gets the URL's filename by formatting its MD5 hash as UNICODE hex
  135. //--------------------------------------------------------------------------
  136. VOID
  137. WINAPI
  138. I_SchemeGetUrlFileName(
  139. IN LPCWSTR pwszUrl,
  140. OUT WCHAR wszUrlFileName[SCHEME_URL_FILENAME_LEN]
  141. )
  142. {
  143. MD5_CTX md5ctx;
  144. MD5Init(&md5ctx);
  145. MD5Update(&md5ctx, (const BYTE *) pwszUrl, wcslen(pwszUrl) * sizeof(WCHAR));
  146. MD5Final(&md5ctx);
  147. // convert to a string
  148. I_SchemeBytesToWStr(MD5DIGESTLEN, md5ctx.digest, wszUrlFileName);
  149. }
  150. static DWORD rgdwCreateFileRetryMilliseconds[] =
  151. { 1, 10, 100, 500, 1000, 5000 };
  152. #define MAX_CREATE_FILE_RETRY_COUNT \
  153. (sizeof(rgdwCreateFileRetryMilliseconds) / \
  154. sizeof(rgdwCreateFileRetryMilliseconds[0]))
  155. //+-------------------------------------------------------------------------
  156. // For ERROR_SHARING_VIOLATION or ERROR_ACCESS_DENIED errors returned
  157. // by CreateFileW(), retries after sleeping the above times.
  158. //
  159. // Note, the file to be created is under %UserProfile%. Therefore, unless
  160. // opened by another thread shouldn't get the above errors.
  161. //
  162. // If unable to create the file, returns NULL and not INVALID_HANDLE_VALUE.
  163. //--------------------------------------------------------------------------
  164. HANDLE
  165. WINAPI
  166. I_SchemeCreateFile(
  167. IN LPCWSTR pwszFileName,
  168. IN BOOL fWrite
  169. )
  170. {
  171. HANDLE hFile = INVALID_HANDLE_VALUE;
  172. DWORD dwErr;
  173. DWORD dwRetryCount;
  174. dwRetryCount = 0;
  175. while (INVALID_HANDLE_VALUE == (hFile = CreateFileW(
  176. pwszFileName,
  177. fWrite ? (GENERIC_WRITE | GENERIC_READ) : GENERIC_READ,
  178. fWrite ? 0 : FILE_SHARE_READ,
  179. NULL, // lpsa
  180. fWrite ? CREATE_ALWAYS : OPEN_EXISTING,
  181. fWrite ? FILE_ATTRIBUTE_SYSTEM : FILE_ATTRIBUTE_NORMAL,
  182. NULL // hTemplateFile
  183. ))) {
  184. dwErr = GetLastError();
  185. if ((ERROR_SHARING_VIOLATION == dwErr ||
  186. ERROR_ACCESS_DENIED == dwErr) &&
  187. MAX_CREATE_FILE_RETRY_COUNT > dwRetryCount) {
  188. Sleep(rgdwCreateFileRetryMilliseconds[dwRetryCount]);
  189. dwRetryCount++;
  190. } else {
  191. if (ERROR_PATH_NOT_FOUND == dwErr)
  192. dwErr = ERROR_FILE_NOT_FOUND;
  193. goto CreateFileError;
  194. }
  195. }
  196. CommonReturn:
  197. return hFile;
  198. ErrorReturn:
  199. hFile = NULL;
  200. goto CommonReturn;
  201. SET_ERROR_VAR(CreateFileError, dwErr)
  202. }
  203. //+-------------------------------------------------------------------------
  204. // The MetaData file is always opened first and closed last.
  205. // Its opened for writing without sharing.
  206. //--------------------------------------------------------------------------
  207. BOOL
  208. WINAPI
  209. I_SchemeCreateCacheFiles(
  210. IN LPCWSTR pwszUrl,
  211. IN BOOL fWrite,
  212. OUT HANDLE *phMetaDataFile,
  213. OUT HANDLE *phContentFile
  214. )
  215. {
  216. BOOL fResult;
  217. LPWSTR pwszCryptnetUrlCacheDir = NULL;
  218. DWORD cchCryptnetUrlCacheDir;
  219. LPWSTR pwszMetaDataFile = NULL;
  220. LPWSTR pwszContentFile = NULL;
  221. HANDLE hMetaDataFile = NULL;
  222. HANDLE hContentFile = NULL;
  223. WCHAR wszUrlFileName[SCHEME_URL_FILENAME_LEN];
  224. pwszCryptnetUrlCacheDir = I_SchemeGetCryptnetUrlCacheDir();
  225. if (NULL == pwszCryptnetUrlCacheDir)
  226. goto GetCryptnetUrlCacheDirError;
  227. cchCryptnetUrlCacheDir = wcslen(pwszCryptnetUrlCacheDir);
  228. pwszMetaDataFile = (LPWSTR) PkiNonzeroAlloc(
  229. (cchCryptnetUrlCacheDir + wcslen(SCHEME_META_DATA_SUBDIR) + 1 +
  230. SCHEME_URL_FILENAME_LEN) * sizeof(WCHAR));
  231. pwszContentFile = (LPWSTR) PkiNonzeroAlloc(
  232. (cchCryptnetUrlCacheDir + wcslen(SCHEME_CONTENT_SUBDIR) + 1 +
  233. SCHEME_URL_FILENAME_LEN) * sizeof(WCHAR));
  234. if (NULL == pwszMetaDataFile || NULL == pwszContentFile)
  235. goto OutOfMemory;
  236. wcscpy(pwszMetaDataFile, pwszCryptnetUrlCacheDir);
  237. wcscat(pwszMetaDataFile, SCHEME_META_DATA_SUBDIR);
  238. wcscpy(pwszContentFile, pwszCryptnetUrlCacheDir);
  239. wcscat(pwszContentFile, SCHEME_CONTENT_SUBDIR);
  240. if (fWrite) {
  241. if (!I_RecursiveCreateDirectory(pwszMetaDataFile, NULL))
  242. goto CreateMetaDataDirError;
  243. if (!I_RecursiveCreateDirectory(pwszContentFile, NULL))
  244. goto CreateContentDirError;
  245. }
  246. I_SchemeGetUrlFileName(pwszUrl, wszUrlFileName);
  247. wcscat(pwszMetaDataFile, L"\\");
  248. wcscat(pwszMetaDataFile, wszUrlFileName);
  249. hMetaDataFile = I_SchemeCreateFile(pwszMetaDataFile, fWrite);
  250. if (NULL == hMetaDataFile)
  251. goto CreateMetaDataFileError;
  252. wcscat(pwszContentFile, L"\\");
  253. wcscat(pwszContentFile, wszUrlFileName);
  254. hContentFile = I_SchemeCreateFile(pwszContentFile, fWrite);
  255. if (NULL == hContentFile)
  256. goto CreateContentFileError;
  257. fResult = TRUE;
  258. CommonReturn:
  259. PkiFree(pwszCryptnetUrlCacheDir);
  260. PkiFree(pwszMetaDataFile);
  261. PkiFree(pwszContentFile);
  262. *phMetaDataFile = hMetaDataFile;
  263. *phContentFile = hContentFile;
  264. return fResult;
  265. ErrorReturn:
  266. if (NULL != hContentFile) {
  267. I_SchemeCloseHandle(hContentFile);
  268. hContentFile = NULL;
  269. }
  270. if (NULL != hMetaDataFile) {
  271. I_SchemeCloseHandle(hMetaDataFile);
  272. hMetaDataFile = NULL;
  273. }
  274. fResult = FALSE;
  275. goto CommonReturn;
  276. TRACE_ERROR(GetCryptnetUrlCacheDirError)
  277. TRACE_ERROR(OutOfMemory)
  278. TRACE_ERROR(CreateMetaDataDirError)
  279. TRACE_ERROR(CreateContentDirError)
  280. TRACE_ERROR(CreateMetaDataFileError)
  281. TRACE_ERROR(CreateContentFileError)
  282. }
  283. //+-------------------------------------------------------------------------
  284. // The returned MetaDataHeader must be freed via PkiFree(). Returns NULL
  285. // for any errors. pcbBlob and pwszUrl point to memory following the
  286. // header and don't need to be freed.
  287. //
  288. // The pwsUrl is guaranteed to be NULL terminated.
  289. //--------------------------------------------------------------------------
  290. PSCHEME_CACHE_META_DATA_HEADER
  291. WINAPI
  292. I_SchemeReadAndValidateMetaDataFile(
  293. IN HANDLE hMetaDataFile,
  294. OUT OPTIONAL DWORD **ppcbBlob, // Not allocated
  295. OUT OPTIONAL LPCWSTR *ppwszUrl // Not allocated
  296. )
  297. {
  298. PSCHEME_CACHE_META_DATA_HEADER pMetaDataHeader = NULL;
  299. DWORD *pcbBlob = NULL;
  300. LPWSTR pwszUrl = NULL;
  301. DWORD cbMetaData;
  302. DWORD cbBytesRead;
  303. DWORD cBlob;
  304. DWORD cchUrl;
  305. DWORD dwUrlOffset;
  306. cbMetaData = GetFileSize(hMetaDataFile, NULL);
  307. if (INVALID_FILE_SIZE == cbMetaData ||
  308. sizeof(SCHEME_CACHE_META_DATA_HEADER) > cbMetaData)
  309. goto InvalidMetaDataFile;
  310. pMetaDataHeader = (PSCHEME_CACHE_META_DATA_HEADER) PkiZeroAlloc(
  311. cbMetaData);
  312. if (NULL == pMetaDataHeader)
  313. goto OutOfMemory;
  314. if (!ReadFile(
  315. hMetaDataFile,
  316. pMetaDataHeader,
  317. cbMetaData,
  318. &cbBytesRead,
  319. NULL // lpOverlapped
  320. ) || cbMetaData != cbBytesRead)
  321. goto ReadMetaDataFileError;
  322. cBlob = pMetaDataHeader->cBlob;
  323. if (sizeof(SCHEME_CACHE_META_DATA_HEADER) > pMetaDataHeader->cbSize ||
  324. cbMetaData < pMetaDataHeader->cbSize ||
  325. 0 != (pMetaDataHeader->cbSize % sizeof(DWORD)) ||
  326. cBlob > (cbMetaData - pMetaDataHeader->cbSize) / sizeof(DWORD))
  327. goto InvalidMetaDataFile;
  328. pcbBlob = (DWORD *) (((BYTE*)pMetaDataHeader) + pMetaDataHeader->cbSize);
  329. cchUrl = pMetaDataHeader->cbUrl / sizeof(WCHAR);
  330. dwUrlOffset = pMetaDataHeader->cbSize + sizeof(DWORD) * cBlob;
  331. if (0 == cchUrl ||
  332. cchUrl > (cbMetaData - dwUrlOffset) / sizeof(WCHAR))
  333. goto InvalidMetaDataFile;
  334. pwszUrl = (LPWSTR) (((BYTE*)pMetaDataHeader) + dwUrlOffset);
  335. pwszUrl[cchUrl - 1] = L'\0';
  336. CommonReturn:
  337. if (ppcbBlob)
  338. *ppcbBlob = pcbBlob;
  339. if (ppwszUrl)
  340. *ppwszUrl = (LPCWSTR) pwszUrl;
  341. return pMetaDataHeader;
  342. ErrorReturn:
  343. if (pMetaDataHeader) {
  344. PkiFree(pMetaDataHeader);
  345. pMetaDataHeader = NULL;
  346. }
  347. pcbBlob = NULL;
  348. pwszUrl = NULL;
  349. goto CommonReturn;
  350. SET_ERROR(InvalidMetaDataFile, CRYPT_E_FILE_ERROR)
  351. TRACE_ERROR(OutOfMemory)
  352. TRACE_ERROR(ReadMetaDataFileError)
  353. }
  354. //+---------------------------------------------------------------------------
  355. //
  356. // Function: SchemeCacheCryptBlobArray
  357. //
  358. // Synopsis: cache the crypt blob array under the given URL
  359. //
  360. //----------------------------------------------------------------------------
  361. BOOL WINAPI
  362. SchemeCacheCryptBlobArray (
  363. IN LPCWSTR pwszUrl,
  364. IN DWORD dwRetrievalFlags,
  365. IN PCRYPT_BLOB_ARRAY pcba,
  366. IN PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
  367. )
  368. {
  369. BOOL fResult;
  370. SCHEME_CACHE_META_DATA_HEADER MetaDataHeader;
  371. HANDLE hMetaDataFile = NULL;
  372. HANDLE hContentFile = NULL;
  373. DWORD cbBytesWritten;
  374. DWORD i;
  375. if (!I_SchemeCreateCacheFiles(
  376. pwszUrl,
  377. TRUE, // fWrite
  378. &hMetaDataFile,
  379. &hContentFile
  380. ))
  381. goto CreateCacheFilesError;
  382. memset(&MetaDataHeader, 0, sizeof(MetaDataHeader));
  383. MetaDataHeader.cbSize = sizeof(MetaDataHeader);
  384. MetaDataHeader.dwMagic = SCHEME_CACHE_META_DATA_MAGIC;
  385. MetaDataHeader.cBlob = pcba->cBlob;
  386. MetaDataHeader.cbUrl = (wcslen(pwszUrl) + 1) * sizeof(WCHAR);
  387. GetSystemTimeAsFileTime(&MetaDataHeader.LastSyncTime);
  388. if (!WriteFile(
  389. hMetaDataFile,
  390. &MetaDataHeader,
  391. sizeof(MetaDataHeader),
  392. &cbBytesWritten,
  393. NULL // lpOverlapped
  394. ))
  395. goto WriteMetaDataHeaderError;
  396. for (i = 0; i < pcba->cBlob; i++) {
  397. DWORD cbBlob = pcba->rgBlob[i].cbData;
  398. if (!WriteFile(
  399. hMetaDataFile,
  400. &cbBlob,
  401. sizeof(cbBlob),
  402. &cbBytesWritten,
  403. NULL // lpOverlapped
  404. ))
  405. goto WriteBlobLengthError;
  406. if (0 != cbBlob) {
  407. if (!WriteFile(
  408. hContentFile,
  409. pcba->rgBlob[i].pbData,
  410. cbBlob,
  411. &cbBytesWritten,
  412. NULL // lpOverlapped
  413. ))
  414. goto WriteBlobContentError;
  415. }
  416. }
  417. if (!WriteFile(
  418. hMetaDataFile,
  419. pwszUrl,
  420. MetaDataHeader.cbUrl,
  421. &cbBytesWritten,
  422. NULL // lpOverlapped
  423. ))
  424. goto WriteUrlError;
  425. if (pAuxInfo &&
  426. offsetof(CRYPT_RETRIEVE_AUX_INFO, pLastSyncTime) <
  427. pAuxInfo->cbSize && pAuxInfo->pLastSyncTime)
  428. *pAuxInfo->pLastSyncTime = MetaDataHeader.LastSyncTime;
  429. fResult = TRUE;
  430. CommonReturn:
  431. if (NULL != hContentFile)
  432. I_SchemeCloseHandle(hContentFile);
  433. if (NULL != hMetaDataFile)
  434. I_SchemeCloseHandle(hMetaDataFile);
  435. return fResult;
  436. ErrorReturn:
  437. fResult = FALSE;
  438. goto CommonReturn;
  439. TRACE_ERROR(CreateCacheFilesError)
  440. TRACE_ERROR(WriteMetaDataHeaderError)
  441. TRACE_ERROR(WriteBlobLengthError)
  442. TRACE_ERROR(WriteBlobContentError)
  443. TRACE_ERROR(WriteUrlError)
  444. }
  445. //+---------------------------------------------------------------------------
  446. //
  447. // Function: SchemeRetrieveCachedCryptBlobArray
  448. //
  449. // Synopsis: retrieve cached blob array bits
  450. //
  451. //----------------------------------------------------------------------------
  452. BOOL WINAPI
  453. SchemeRetrieveCachedCryptBlobArray (
  454. IN LPCWSTR pwszUrl,
  455. IN DWORD dwRetrievalFlags,
  456. OUT PCRYPT_BLOB_ARRAY pcba,
  457. OUT PFN_FREE_ENCODED_OBJECT_FUNC* ppfnFreeObject,
  458. OUT LPVOID* ppvFreeContext,
  459. IN OUT PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
  460. )
  461. {
  462. BOOL fResult;
  463. HANDLE hMetaDataFile = NULL;
  464. HANDLE hContentFile = NULL;
  465. PSCHEME_CACHE_META_DATA_HEADER pMetaDataHeader = NULL;
  466. DWORD *pcbBlob; // not allocated
  467. DWORD cbContent;
  468. DWORD cBlob;
  469. PCRYPT_BLOB_ARRAY pCachedArray = NULL;
  470. PCRYPT_DATA_BLOB pBlob; // not allocated
  471. BYTE *pbBlob; // not allocated
  472. DWORD cbBlobHeader;
  473. DWORD cbBytesRead;
  474. DWORD i;
  475. if (!I_SchemeCreateCacheFiles(
  476. pwszUrl,
  477. FALSE, // fWrite
  478. &hMetaDataFile,
  479. &hContentFile
  480. ))
  481. goto CreateCacheFilesError;
  482. pMetaDataHeader = I_SchemeReadAndValidateMetaDataFile(
  483. hMetaDataFile,
  484. &pcbBlob,
  485. NULL // ppwszUrl
  486. );
  487. if (NULL == pMetaDataHeader)
  488. goto ReadMetaDataFileError;
  489. cBlob = pMetaDataHeader->cBlob;
  490. cbContent = 0;
  491. for (i = 0; i < cBlob; i++)
  492. cbContent += pcbBlob[i];
  493. cbBlobHeader = sizeof(CRYPT_BLOB_ARRAY) + cBlob * sizeof(CRYPT_DATA_BLOB);
  494. pCachedArray = (PCRYPT_BLOB_ARRAY) PkiZeroAlloc(
  495. cbBlobHeader + cbContent);
  496. if (NULL == pCachedArray)
  497. goto OutOfMemory;
  498. pBlob = (PCRYPT_DATA_BLOB) &pCachedArray[1];
  499. pbBlob = (BYTE *) &pBlob[cBlob];
  500. if (0 != cbContent) {
  501. if (!ReadFile(
  502. hContentFile,
  503. pbBlob,
  504. cbContent,
  505. &cbBytesRead,
  506. NULL // lpOverlapped
  507. ) || cbContent != cbBytesRead)
  508. goto ReadContentFileError;
  509. }
  510. pCachedArray->cBlob = cBlob;
  511. pCachedArray->rgBlob = pBlob;
  512. for (i = 0; i < cBlob; i++) {
  513. pBlob[i].cbData = pcbBlob[i];
  514. pBlob[i].pbData = pbBlob;
  515. pbBlob += pcbBlob[i];
  516. }
  517. pcba->cBlob = pCachedArray->cBlob;
  518. pcba->rgBlob = pCachedArray->rgBlob;
  519. *ppfnFreeObject = SchemeFreeEncodedCryptBlobArray;
  520. *ppvFreeContext = (LPVOID) pCachedArray;
  521. if (pAuxInfo && offsetof(CRYPT_RETRIEVE_AUX_INFO, pLastSyncTime) <
  522. pAuxInfo->cbSize && pAuxInfo->pLastSyncTime)
  523. *pAuxInfo->pLastSyncTime = pMetaDataHeader->LastSyncTime;
  524. fResult = TRUE;
  525. CommonReturn:
  526. if (NULL != hContentFile)
  527. I_SchemeCloseHandle(hContentFile);
  528. if (NULL != hMetaDataFile)
  529. I_SchemeCloseHandle(hMetaDataFile);
  530. PkiFree(pMetaDataHeader);
  531. return fResult;
  532. ErrorReturn:
  533. PkiFree(pCachedArray);
  534. fResult = FALSE;
  535. goto CommonReturn;
  536. TRACE_ERROR(CreateCacheFilesError)
  537. TRACE_ERROR(OutOfMemory)
  538. TRACE_ERROR(ReadMetaDataFileError)
  539. TRACE_ERROR(ReadContentFileError)
  540. }
  541. //+-------------------------------------------------------------------------
  542. // For ERROR_SHARING_VIOLATION or ERROR_ACCESS_DENIED errors returned
  543. // by DeleteFileW(), retries after sleeping an increasing array of times.
  544. //
  545. // Note, the file to be deleted is under %UserProfile%. Therefore, unless
  546. // opened by another thread shouldn't get the above errors.
  547. //--------------------------------------------------------------------------
  548. BOOL
  549. WINAPI
  550. I_SchemeDeleteFile(
  551. IN LPCWSTR pwszFileName
  552. )
  553. {
  554. BOOL fResult;
  555. DWORD dwErr;
  556. DWORD dwRetryCount;
  557. dwRetryCount = 0;
  558. while (!DeleteFileU(pwszFileName)) {
  559. dwErr = GetLastError();
  560. if ((ERROR_SHARING_VIOLATION == dwErr ||
  561. ERROR_ACCESS_DENIED == dwErr) &&
  562. MAX_CREATE_FILE_RETRY_COUNT > dwRetryCount) {
  563. Sleep(rgdwCreateFileRetryMilliseconds[dwRetryCount]);
  564. dwRetryCount++;
  565. } else
  566. goto DeleteFileError;
  567. }
  568. fResult = TRUE;
  569. CommonReturn:
  570. return fResult;
  571. ErrorReturn:
  572. fResult = FALSE;
  573. goto CommonReturn;
  574. SET_ERROR_VAR(DeleteFileError, dwErr)
  575. }
  576. //+---------------------------------------------------------------------------
  577. //
  578. // Function: SchemeDeleteUrlCacheEntry
  579. //
  580. // Synopsis: delete URL cache entry
  581. //
  582. // For no cache entry returns FALSE with LastError set to
  583. // ERROR_FILE_NOT_FOUND
  584. //
  585. //----------------------------------------------------------------------------
  586. BOOL WINAPI
  587. SchemeDeleteUrlCacheEntry (
  588. IN LPCWSTR pwszUrl
  589. )
  590. {
  591. BOOL fResult;
  592. LPWSTR pwszCryptnetUrlCacheDir = NULL;
  593. DWORD cchCryptnetUrlCacheDir;
  594. LPWSTR pwszMetaDataFile = NULL;
  595. LPWSTR pwszContentFile = NULL;
  596. WCHAR wszUrlFileName[SCHEME_URL_FILENAME_LEN];
  597. // Format the MetaData and Content filenames
  598. // - %UserProfile%\Microsoft\CryptnetUrlCache\MetaData\14A1AE3A6A7648689AE8F94F367AC606
  599. // - %UserProfile%\Microsoft\CryptnetUrlCache\Content\14A1AE3A6A7648689AE8F94F367AC606
  600. // Where 14A1AE3A6A7648689AE8F94F367AC606 is the Unicode Hex of md5 hash
  601. // of the URL string
  602. pwszCryptnetUrlCacheDir = I_SchemeGetCryptnetUrlCacheDir();
  603. if (NULL == pwszCryptnetUrlCacheDir)
  604. goto GetCryptnetUrlCacheDirError;
  605. cchCryptnetUrlCacheDir = wcslen(pwszCryptnetUrlCacheDir);
  606. pwszMetaDataFile = (LPWSTR) PkiNonzeroAlloc(
  607. (cchCryptnetUrlCacheDir + wcslen(SCHEME_META_DATA_SUBDIR) + 1 +
  608. SCHEME_URL_FILENAME_LEN) * sizeof(WCHAR));
  609. pwszContentFile = (LPWSTR) PkiNonzeroAlloc(
  610. (cchCryptnetUrlCacheDir + wcslen(SCHEME_CONTENT_SUBDIR) + 1 +
  611. SCHEME_URL_FILENAME_LEN) * sizeof(WCHAR));
  612. if (NULL == pwszMetaDataFile || NULL == pwszContentFile)
  613. goto OutOfMemory;
  614. I_SchemeGetUrlFileName(pwszUrl, wszUrlFileName);
  615. wcscpy(pwszMetaDataFile, pwszCryptnetUrlCacheDir);
  616. wcscat(pwszMetaDataFile, SCHEME_META_DATA_SUBDIR);
  617. wcscat(pwszMetaDataFile, L"\\");
  618. wcscat(pwszMetaDataFile, wszUrlFileName);
  619. wcscpy(pwszContentFile, pwszCryptnetUrlCacheDir);
  620. wcscat(pwszContentFile, SCHEME_CONTENT_SUBDIR);
  621. wcscat(pwszContentFile, L"\\");
  622. wcscat(pwszContentFile, wszUrlFileName);
  623. // Delete both the content and meta data files.
  624. if (!I_SchemeDeleteFile(pwszContentFile)) {
  625. if (ERROR_FILE_NOT_FOUND != GetLastError())
  626. goto DeleteContentFileError;
  627. }
  628. fResult = I_SchemeDeleteFile(pwszMetaDataFile);
  629. CommonReturn:
  630. PkiFree(pwszCryptnetUrlCacheDir);
  631. PkiFree(pwszMetaDataFile);
  632. PkiFree(pwszContentFile);
  633. return fResult;
  634. ErrorReturn:
  635. fResult = FALSE;
  636. goto CommonReturn;
  637. TRACE_ERROR(GetCryptnetUrlCacheDirError)
  638. TRACE_ERROR(OutOfMemory)
  639. TRACE_ERROR(DeleteContentFileError)
  640. }
  641. //+---------------------------------------------------------------------------
  642. //
  643. // Function: SchemeFreeEncodedCryptBlobArray
  644. //
  645. // Synopsis: free encoded crypt blob array
  646. //
  647. //----------------------------------------------------------------------------
  648. VOID WINAPI
  649. SchemeFreeEncodedCryptBlobArray (
  650. IN LPCSTR pszObjectOid,
  651. IN PCRYPT_BLOB_ARRAY pcba,
  652. IN LPVOID pvFreeContext
  653. )
  654. {
  655. PkiFree(pvFreeContext);
  656. }
  657. //+---------------------------------------------------------------------------
  658. //
  659. // Function: SchemeGetPasswordCredentialsW
  660. //
  661. // Synopsis: get password credentials from crypt credentials
  662. //
  663. //----------------------------------------------------------------------------
  664. BOOL WINAPI
  665. SchemeGetPasswordCredentialsW (
  666. IN PCRYPT_CREDENTIALS pCredentials,
  667. OUT PCRYPT_PASSWORD_CREDENTIALSW pPasswordCredentials,
  668. OUT BOOL* pfFreeCredentials
  669. )
  670. {
  671. DWORD cwUsername;
  672. DWORD cwPassword;
  673. PCRYPT_PASSWORD_CREDENTIALSA pPassCredA;
  674. PCRYPT_PASSWORD_CREDENTIALSW pPassCredW;
  675. LPWSTR pszUsername;
  676. LPWSTR pszPassword;
  677. if ( pPasswordCredentials->cbSize != sizeof( CRYPT_PASSWORD_CREDENTIALS ) )
  678. {
  679. SetLastError( (DWORD) E_INVALIDARG );
  680. return( FALSE );
  681. }
  682. if ( pCredentials == NULL )
  683. {
  684. pPasswordCredentials->pszUsername = NULL;
  685. pPasswordCredentials->pszPassword = NULL;
  686. *pfFreeCredentials = FALSE;
  687. return( TRUE );
  688. }
  689. if ( pCredentials->pszCredentialsOid ==
  690. CREDENTIAL_OID_PASSWORD_CREDENTIALS_W )
  691. {
  692. pPassCredW = (PCRYPT_PASSWORD_CREDENTIALSW)pCredentials->pvCredentials;
  693. *pPasswordCredentials = *pPassCredW;
  694. *pfFreeCredentials = FALSE;
  695. return( TRUE );
  696. }
  697. if ( pCredentials->pszCredentialsOid !=
  698. CREDENTIAL_OID_PASSWORD_CREDENTIALS_A )
  699. {
  700. SetLastError( (DWORD) E_INVALIDARG );
  701. return( FALSE );
  702. }
  703. pPassCredA = (PCRYPT_PASSWORD_CREDENTIALSA)pCredentials->pvCredentials;
  704. cwUsername = strlen( pPassCredA->pszUsername ) + 1;
  705. cwPassword = strlen( pPassCredA->pszPassword ) + 1;
  706. pszUsername = new WCHAR [ cwUsername ];
  707. pszPassword = new WCHAR [ cwPassword ];
  708. if ( ( pszUsername == NULL ) || ( pszPassword == NULL ) )
  709. {
  710. delete [] pszUsername;
  711. delete [] pszPassword;
  712. SetLastError( (DWORD) E_OUTOFMEMORY );
  713. return( FALSE );
  714. }
  715. *pfFreeCredentials = TRUE;
  716. MultiByteToWideChar(
  717. CP_ACP,
  718. 0,
  719. pPassCredA->pszUsername,
  720. cwUsername,
  721. pszUsername,
  722. cwUsername
  723. );
  724. pszUsername[cwUsername - 1] = L'\0';
  725. MultiByteToWideChar(
  726. CP_ACP,
  727. 0,
  728. pPassCredA->pszPassword,
  729. cwPassword,
  730. pszPassword,
  731. cwPassword
  732. );
  733. pszPassword[cwPassword - 1] = L'\0';
  734. pPasswordCredentials->pszUsername = pszUsername;
  735. pPasswordCredentials->pszPassword = pszPassword;
  736. return( TRUE );
  737. }
  738. //+---------------------------------------------------------------------------
  739. //
  740. // Function: SchemeFreePasswordCredentialsA
  741. //
  742. // Synopsis: free password credentials
  743. //
  744. //----------------------------------------------------------------------------
  745. VOID WINAPI
  746. SchemeFreePasswordCredentialsW (
  747. IN PCRYPT_PASSWORD_CREDENTIALSW pPasswordCredentials
  748. )
  749. {
  750. DWORD cch;
  751. // Ensure allocated credentials are cleared out before being freed.
  752. if (pPasswordCredentials->pszUsername)
  753. {
  754. cch = wcslen(pPasswordCredentials->pszUsername);
  755. SecureZeroMemory(pPasswordCredentials->pszUsername,
  756. cch * sizeof(WCHAR));
  757. delete [] pPasswordCredentials->pszUsername;
  758. }
  759. if (pPasswordCredentials->pszPassword)
  760. {
  761. cch = wcslen(pPasswordCredentials->pszPassword);
  762. SecureZeroMemory(pPasswordCredentials->pszPassword,
  763. cch * sizeof(WCHAR));
  764. delete [] pPasswordCredentials->pszPassword;
  765. }
  766. }
  767. //+---------------------------------------------------------------------------
  768. //
  769. // Function: SchemeGetAuthIdentityFromPasswordCredentialsW
  770. //
  771. // Synopsis: converts a CRYPT_PASSWORD_CREDENTIALSW to a
  772. // SEC_WINNT_AUTH_IDENTITY_W
  773. //
  774. //----------------------------------------------------------------------------
  775. BOOL WINAPI
  776. SchemeGetAuthIdentityFromPasswordCredentialsW (
  777. IN PCRYPT_PASSWORD_CREDENTIALSW pPasswordCredentials,
  778. OUT PSEC_WINNT_AUTH_IDENTITY_W pAuthIdentity
  779. )
  780. {
  781. DWORD cDomain = 0;
  782. if ( pPasswordCredentials->pszUsername == NULL )
  783. {
  784. pAuthIdentity->User = NULL;
  785. pAuthIdentity->UserLength = 0;
  786. pAuthIdentity->Domain = NULL;
  787. pAuthIdentity->DomainLength = 0;
  788. pAuthIdentity->Password = NULL;
  789. pAuthIdentity->PasswordLength = 0;
  790. pAuthIdentity->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  791. return TRUE;
  792. }
  793. while ( ( pPasswordCredentials->pszUsername[cDomain] != L'\0' ) &&
  794. ( pPasswordCredentials->pszUsername[cDomain] != L'\\' ) )
  795. {
  796. cDomain += 1;
  797. }
  798. if ( cDomain != (DWORD)wcslen( pPasswordCredentials->pszUsername ) )
  799. {
  800. LPWSTR pwszDomain;
  801. pwszDomain = new WCHAR [ cDomain + 1 ];
  802. if ( pwszDomain == NULL )
  803. {
  804. SetLastError( (DWORD) E_OUTOFMEMORY );
  805. return( FALSE );
  806. }
  807. memcpy(pwszDomain, pPasswordCredentials->pszUsername,
  808. cDomain * sizeof(WCHAR));
  809. pwszDomain[cDomain] = L'\0';
  810. pAuthIdentity->Domain = (USHORT *)pwszDomain;
  811. pAuthIdentity->DomainLength = cDomain;
  812. pAuthIdentity->User = (USHORT *)&pPasswordCredentials->pszUsername[
  813. cDomain+1
  814. ];
  815. pAuthIdentity->UserLength = wcslen( (LPCWSTR)pAuthIdentity->User );
  816. }
  817. else
  818. {
  819. pAuthIdentity->Domain = NULL;
  820. pAuthIdentity->DomainLength = 0;
  821. pAuthIdentity->User = (USHORT *)pPasswordCredentials->pszUsername;
  822. pAuthIdentity->UserLength = cDomain;
  823. }
  824. pAuthIdentity->Password = (USHORT *)pPasswordCredentials->pszPassword;
  825. pAuthIdentity->PasswordLength = wcslen( (LPCWSTR)pAuthIdentity->Password );
  826. pAuthIdentity->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  827. return TRUE;
  828. }
  829. //+---------------------------------------------------------------------------
  830. //
  831. // Function: SchemeFreeAuthIdentityFromPasswordCredentialsW
  832. //
  833. // Synopsis: restore the backslash to the domain username pair
  834. //
  835. //----------------------------------------------------------------------------
  836. VOID WINAPI
  837. SchemeFreeAuthIdentityFromPasswordCredentialsW (
  838. IN PCRYPT_PASSWORD_CREDENTIALSW pPasswordCredentials,
  839. IN OUT PSEC_WINNT_AUTH_IDENTITY_W pAuthIdentity
  840. )
  841. {
  842. if ( pAuthIdentity->Domain != NULL )
  843. {
  844. DWORD dwLastError = GetLastError();
  845. delete [] pAuthIdentity->Domain;
  846. SetLastError(dwLastError);
  847. }
  848. }
  849. //+---------------------------------------------------------------------------
  850. //
  851. // Function: SchemeRetrieveUncachedAuxInfo
  852. //
  853. // Synopsis: update the LastSyncTime in the retrieval AuxInfo with the
  854. // current time.
  855. //
  856. //----------------------------------------------------------------------------
  857. BOOL WINAPI
  858. SchemeRetrieveUncachedAuxInfo (
  859. IN PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
  860. )
  861. {
  862. if ( pAuxInfo &&
  863. offsetof(CRYPT_RETRIEVE_AUX_INFO, pLastSyncTime) <
  864. pAuxInfo->cbSize &&
  865. pAuxInfo->pLastSyncTime )
  866. {
  867. GetSystemTimeAsFileTime( pAuxInfo->pLastSyncTime );
  868. }
  869. return( TRUE );
  870. }
  871. //+-------------------------------------------------------------------------
  872. // Iterate through the Url Cache MetaData files in:
  873. // %UserProfile%\Microsoft\CryptnetUrlCache\MetaData
  874. //--------------------------------------------------------------------------
  875. BOOL
  876. WINAPI
  877. I_CryptNetEnumUrlCacheEntry(
  878. IN DWORD dwFlags,
  879. IN LPVOID pvReserved,
  880. IN LPVOID pvArg,
  881. IN PFN_CRYPTNET_ENUM_URL_CACHE_ENTRY_CALLBACK pfnEnumCallback
  882. )
  883. {
  884. BOOL fResult;
  885. DWORD dwLastError = 0;
  886. DWORD cchCryptnetUrlCacheDir;
  887. LPWSTR pwszCryptnetUrlCacheDir = NULL;
  888. DWORD cchMetaDataDir;
  889. LPWSTR pwszMetaDataFile = NULL;
  890. DWORD cchContentDir;
  891. LPWSTR pwszContentFile = NULL;
  892. HANDLE hFindFile = INVALID_HANDLE_VALUE;
  893. WIN32_FIND_DATAW FindFileData;
  894. pwszCryptnetUrlCacheDir = I_SchemeGetCryptnetUrlCacheDir();
  895. if (NULL == pwszCryptnetUrlCacheDir)
  896. goto GetCryptnetUrlCacheDirError;
  897. cchCryptnetUrlCacheDir = wcslen(pwszCryptnetUrlCacheDir);
  898. cchMetaDataDir = cchCryptnetUrlCacheDir + SCHEME_CCH_META_DATA_SUBDIR + 1;
  899. cchContentDir = cchCryptnetUrlCacheDir + SCHEME_CCH_CONTENT_SUBDIR + 1;
  900. pwszMetaDataFile = (LPWSTR) PkiNonzeroAlloc(
  901. (cchMetaDataDir + SCHEME_URL_FILENAME_LEN) * sizeof(WCHAR));
  902. pwszContentFile = (LPWSTR) PkiNonzeroAlloc(
  903. (cchContentDir + SCHEME_URL_FILENAME_LEN) * sizeof(WCHAR));
  904. if (NULL == pwszMetaDataFile || NULL == pwszContentFile)
  905. goto OutOfMemory;
  906. memcpy(pwszMetaDataFile, pwszCryptnetUrlCacheDir,
  907. cchCryptnetUrlCacheDir * sizeof(WCHAR));
  908. memcpy(pwszMetaDataFile + cchCryptnetUrlCacheDir,
  909. SCHEME_META_DATA_SUBDIR,
  910. SCHEME_CCH_META_DATA_SUBDIR * sizeof(WCHAR));
  911. wcscpy(&pwszMetaDataFile[cchMetaDataDir - 1], L"\\*");
  912. if (INVALID_HANDLE_VALUE == (hFindFile = FindFirstFileW(
  913. pwszMetaDataFile,
  914. &FindFileData
  915. ))) {
  916. dwLastError = GetLastError();
  917. if (ERROR_PATH_NOT_FOUND == dwLastError)
  918. dwLastError = ERROR_FILE_NOT_FOUND;
  919. goto FindFirstFileError;
  920. }
  921. memcpy(pwszContentFile, pwszCryptnetUrlCacheDir,
  922. cchCryptnetUrlCacheDir * sizeof(WCHAR));
  923. memcpy(pwszContentFile + cchCryptnetUrlCacheDir,
  924. SCHEME_CONTENT_SUBDIR, SCHEME_CCH_CONTENT_SUBDIR * sizeof(WCHAR));
  925. pwszContentFile[cchContentDir - 1] = L'\\';
  926. while (TRUE) {
  927. DWORD cchFileName = wcslen(FindFileData.cFileName);
  928. if (0 == (FILE_ATTRIBUTE_DIRECTORY & FindFileData.dwFileAttributes) &&
  929. 0 == FindFileData.nFileSizeHigh &&
  930. 0 != FindFileData.nFileSizeLow &&
  931. L'\0' != FindFileData.cFileName[0] &&
  932. SCHEME_URL_FILENAME_LEN > cchFileName) {
  933. HANDLE hMetaDataFile;
  934. memcpy(pwszMetaDataFile + cchMetaDataDir,
  935. FindFileData.cFileName, (cchFileName + 1) * sizeof(WCHAR));
  936. memcpy(pwszContentFile + cchContentDir,
  937. FindFileData.cFileName, (cchFileName + 1) * sizeof(WCHAR));
  938. hMetaDataFile = I_SchemeCreateFile(
  939. pwszMetaDataFile,
  940. FALSE // fWrite
  941. );
  942. if (NULL != hMetaDataFile) {
  943. PSCHEME_CACHE_META_DATA_HEADER pMetaDataHeader;
  944. CRYPTNET_URL_CACHE_ENTRY UrlCacheEntry;
  945. pMetaDataHeader = I_SchemeReadAndValidateMetaDataFile(
  946. hMetaDataFile,
  947. &UrlCacheEntry.pcbBlob, // Not allocated
  948. &UrlCacheEntry.pwszUrl // Not allocated
  949. );
  950. I_SchemeCloseHandle(hMetaDataFile);
  951. if (NULL != pMetaDataHeader) {
  952. UrlCacheEntry.cbSize = sizeof(UrlCacheEntry);
  953. UrlCacheEntry.dwMagic = pMetaDataHeader->dwMagic;
  954. UrlCacheEntry.LastSyncTime = pMetaDataHeader->LastSyncTime;
  955. UrlCacheEntry.cBlob = pMetaDataHeader->cBlob;
  956. // UrlCacheEntry.pcbBlob =
  957. // UrlCacheEntry.pwszUrl =
  958. UrlCacheEntry.pwszMetaDataFileName = pwszMetaDataFile;
  959. UrlCacheEntry.pwszContentFileName = pwszContentFile;
  960. fResult = pfnEnumCallback(
  961. &UrlCacheEntry,
  962. 0, // dwFlags
  963. NULL, // pvReserved
  964. pvArg
  965. );
  966. PkiFree(pMetaDataHeader);
  967. if (!fResult)
  968. goto ErrorReturn;
  969. }
  970. }
  971. }
  972. if (!FindNextFileW(hFindFile, &FindFileData)) {
  973. dwLastError = GetLastError();
  974. if (ERROR_NO_MORE_FILES == dwLastError)
  975. goto SuccessReturn;
  976. else
  977. goto FindNextFileError;
  978. }
  979. }
  980. SuccessReturn:
  981. fResult = TRUE;
  982. CommonReturn:
  983. PkiFree(pwszCryptnetUrlCacheDir);
  984. PkiFree(pwszMetaDataFile);
  985. PkiFree(pwszContentFile);
  986. if (INVALID_HANDLE_VALUE != hFindFile)
  987. FindClose(hFindFile);
  988. SetLastError(dwLastError);
  989. return fResult;
  990. ErrorReturn:
  991. dwLastError = GetLastError();
  992. fResult = FALSE;
  993. goto CommonReturn;
  994. TRACE_ERROR(GetCryptnetUrlCacheDirError)
  995. TRACE_ERROR(OutOfMemory)
  996. SET_ERROR_VAR(FindFirstFileError, dwLastError)
  997. SET_ERROR_VAR(FindNextFileError, dwLastError)
  998. }