Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6133 lines
170 KiB

  1. /*++
  2. Copyright (c) 1997, 1998, 1999 Microsoft Corporation
  3. Module Name:
  4. keyman.cpp
  5. Abstract:
  6. This module contains routines to read and write data (key containers) from
  7. and to files.
  8. Author:
  9. 16 Mar 98 jeffspel
  10. --*/
  11. // Don't whine about unnamed unions
  12. #pragma warning (disable: 4201)
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #include <crypt.h>
  17. #include <windows.h>
  18. #include <userenv.h>
  19. #include <userenvp.h> // for GetUserAppDataPathW
  20. #include <wincrypt.h>
  21. #include <cspdk.h>
  22. #include <rpc.h>
  23. #include <shlobj.h>
  24. #include <contman.h>
  25. #include <md5.h>
  26. #include <des.h>
  27. #include <modes.h>
  28. #include <csprc.h>
  29. #include <crtdbg.h>
  30. #ifdef USE_HW_RNG
  31. #ifdef _M_IX86
  32. #include <winioctl.h>
  33. // INTEL h files for on chip RNG
  34. #include "deftypes.h" //ISD typedefs and constants
  35. #include "ioctldef.h" //ISD ioctl definitions
  36. #endif // _M_IX86
  37. #endif // USE_HW_RNG
  38. static LPBYTE l_pbStringBlock = NULL;
  39. CSP_STRINGS g_Strings = {
  40. NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  41. NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  42. NULL, NULL, NULL, NULL, NULL, NULL };
  43. typedef struct _OLD_KEY_CONTAINER_LENS_
  44. {
  45. DWORD cbSigPub;
  46. DWORD cbSigEncPriv;
  47. DWORD cbExchPub;
  48. DWORD cbExchEncPriv;
  49. } OLD_KEY_CONTAINER_LENS, *POLD_KEY_CONTAINER_LENS;
  50. #define OLD_KEY_CONTAINER_FILE_FORMAT_VER 1
  51. #define FAST_BUF_SIZE 256
  52. #define ContInfoAlloc(cb) ContAlloc(cb)
  53. #define ContInfoReAlloc(pb, cb) ContRealloc(pb, cb)
  54. #define ContInfoFree(pb) ContFree(pb)
  55. #define MACHINE_KEYS_DIR L"MachineKeys"
  56. // Location of the keys in the registry (minus the logon name)
  57. // Length of the full location (including the logon name)
  58. #define RSA_REG_KEY_LOC "Software\\Microsoft\\Cryptography\\UserKeys"
  59. #define RSA_REG_KEY_LOC_LEN sizeof(RSA_REG_KEY_LOC)
  60. #define RSA_MACH_REG_KEY_LOC "Software\\Microsoft\\Cryptography\\MachineKeys"
  61. #define RSA_MACH_REG_KEY_LOC_LEN sizeof(RSA_MACH_REG_KEY_LOC)
  62. #define DSS_REG_KEY_LOC "Software\\Microsoft\\Cryptography\\DSSUserKeys"
  63. #define DSS_REG_KEY_LOC_LEN sizeof(DSS_REG_KEY_LOC)
  64. #define DSS_MACH_REG_KEY_LOC "Software\\Microsoft\\Cryptography\\DSSUserKeys"
  65. #define DSS_MACH_REG_KEY_LOC_LEN sizeof(DSS_MACH_REG_KEY_LOC)
  66. #define MAX_DPAPI_RETRY_COUNT 5
  67. //
  68. // Memory allocation support.
  69. //
  70. #ifndef ASSERT
  71. #define ASSERT _ASSERTE
  72. #endif
  73. #ifdef _X86_
  74. #define InterlockedAccess(pl) *(pl)
  75. #define InterlockedPointerAccess(ppv) *(ppv)
  76. #else
  77. #define InterlockedAccess(pl) InterlockedExchangeAdd((pl), 0)
  78. #define InterlockedPointerAccess(ppv) InterlockedExchangePointer((ppv), *(ppv))
  79. #endif
  80. #define CONT_HEAP_FLAGS (HEAP_ZERO_MEMORY)
  81. // Scrub sensitive data from memory
  82. extern void
  83. memnuke(
  84. volatile BYTE *pData,
  85. DWORD dwLen);
  86. LPVOID
  87. ContAlloc(
  88. ULONG cbLen)
  89. {
  90. return HeapAlloc(GetProcessHeap(), CONT_HEAP_FLAGS, cbLen);
  91. }
  92. LPVOID
  93. ContRealloc(
  94. LPVOID pvMem,
  95. ULONG cbLen)
  96. {
  97. return HeapReAlloc(GetProcessHeap(), CONT_HEAP_FLAGS, pvMem, cbLen);
  98. }
  99. void
  100. ContFree(
  101. LPVOID pvMem)
  102. {
  103. if (NULL != pvMem)
  104. HeapFree(GetProcessHeap(), CONT_HEAP_FLAGS, pvMem);
  105. }
  106. //
  107. // Wrapper for RtlEncryptMemory, which returns an NTSTATUS. The return
  108. // value is translated to a winerror code.
  109. //
  110. DWORD MyRtlEncryptMemory(
  111. IN PVOID pvMem,
  112. IN DWORD cbMem)
  113. {
  114. NTSTATUS status = RtlEncryptMemory(pvMem, cbMem, 0);
  115. return RtlNtStatusToDosError(status);
  116. }
  117. //
  118. // Wrapper for RtlDecryptMemory, which returns an NTSTATUS. The return value
  119. // is translated to a winerror code.
  120. //
  121. DWORD MyRtlDecryptMemory(
  122. IN PVOID pvMem,
  123. IN DWORD cbMem)
  124. {
  125. NTSTATUS status = RtlDecryptMemory(pvMem, cbMem, 0);
  126. return RtlNtStatusToDosError(status);
  127. }
  128. //
  129. // Return TRUE if Force High Key Protection is set on this machine, return
  130. // FALSE otherwise.
  131. //
  132. BOOL IsForceHighProtectionEnabled(
  133. IN PKEY_CONTAINER_INFO pContInfo)
  134. {
  135. return pContInfo->fForceHighKeyProtection;
  136. }
  137. //
  138. // Retrieves the Force High Key Protection setting for this machine from the
  139. // registry.
  140. //
  141. DWORD InitializeForceHighProtection(
  142. IN OUT PKEY_CONTAINER_INFO pContInfo)
  143. {
  144. HKEY hKey = 0;
  145. DWORD dwSts = ERROR_SUCCESS;
  146. DWORD cbData = 0;
  147. DWORD dwValue = 0;
  148. pContInfo->fForceHighKeyProtection = FALSE;
  149. //
  150. // Open the Cryptography key
  151. //
  152. dwSts = RegOpenKeyEx(
  153. HKEY_LOCAL_MACHINE,
  154. szKEY_CRYPTOAPI_PRIVATE_KEY_OPTIONS,
  155. 0,
  156. KEY_READ | KEY_WOW64_64KEY,
  157. &hKey);
  158. if (ERROR_FILE_NOT_FOUND == dwSts)
  159. {
  160. // Key doesn't exist. Assume feature should remain off.
  161. dwSts = ERROR_SUCCESS;
  162. goto Ret;
  163. }
  164. if (ERROR_SUCCESS != dwSts)
  165. goto Ret;
  166. //
  167. // Find out if force high key protection is on
  168. //
  169. cbData = sizeof(DWORD);
  170. dwSts = RegQueryValueEx(
  171. hKey,
  172. szFORCE_KEY_PROTECTION,
  173. 0,
  174. NULL,
  175. (PBYTE) &dwValue,
  176. &cbData);
  177. if (ERROR_SUCCESS == dwSts && dwFORCE_KEY_PROTECTION_HIGH == dwValue)
  178. pContInfo->fForceHighKeyProtection = TRUE;
  179. else if (ERROR_FILE_NOT_FOUND == dwSts)
  180. // If the value isn't present, assume Force High is turned off.
  181. dwSts = ERROR_SUCCESS;
  182. Ret:
  183. if (hKey)
  184. RegCloseKey(hKey);
  185. return dwSts;
  186. }
  187. //
  188. // Returns True is the cached private key of the indicated type
  189. // is still valid.
  190. //
  191. // Returns False if no cached key is available, or if the available
  192. // cached key is stale.
  193. //
  194. BOOL IsCachedKeyValid(
  195. IN PKEY_CONTAINER_INFO pContInfo,
  196. IN BOOL fSigKey)
  197. {
  198. DWORD *pdwPreviousTimestamp = NULL;
  199. // If the new caching behavior isn't enabled, let the
  200. // caller proceed as before.
  201. if (FALSE == pContInfo->fCachePrivateKeys)
  202. return TRUE;
  203. if (fSigKey)
  204. pdwPreviousTimestamp = &pContInfo->dwSigKeyTimestamp;
  205. else
  206. pdwPreviousTimestamp = &pContInfo->dwKeyXKeyTimestamp;
  207. if ((GetTickCount() - *pdwPreviousTimestamp) >
  208. pContInfo->cMaxKeyLifetime)
  209. {
  210. // Cached key is stale
  211. *pdwPreviousTimestamp = 0;
  212. return FALSE;
  213. }
  214. return TRUE;
  215. }
  216. //
  217. // Updates the cache counter for the key of the indicated type. This
  218. // is called immediately after the key is read from storage, to
  219. // restart the cached key lifetime "countdown."
  220. //
  221. DWORD SetCachedKeyTimestamp(
  222. IN PKEY_CONTAINER_INFO pContInfo,
  223. IN BOOL fSigKey)
  224. {
  225. if (FALSE == pContInfo->fCachePrivateKeys)
  226. return ERROR_SUCCESS;
  227. if (fSigKey)
  228. pContInfo->dwSigKeyTimestamp = GetTickCount();
  229. else
  230. pContInfo->dwKeyXKeyTimestamp = GetTickCount();
  231. return ERROR_SUCCESS;
  232. }
  233. //
  234. // Reads the key cache initialization parameters from the registry.
  235. //
  236. DWORD InitializeKeyCacheInfo(
  237. IN OUT PKEY_CONTAINER_INFO pContInfo)
  238. {
  239. HKEY hKey = 0;
  240. DWORD dwSts = ERROR_SUCCESS;
  241. DWORD cbData = 0;
  242. //
  243. // Open the Cryptography key
  244. //
  245. dwSts = RegOpenKeyEx(
  246. HKEY_LOCAL_MACHINE,
  247. szKEY_CRYPTOAPI_PRIVATE_KEY_OPTIONS,
  248. 0,
  249. KEY_READ | KEY_WOW64_64KEY,
  250. &hKey);
  251. if (ERROR_FILE_NOT_FOUND == dwSts)
  252. {
  253. // Key doesn't exist. Assume feature should remain off.
  254. dwSts = ERROR_SUCCESS;
  255. goto Ret;
  256. }
  257. if (ERROR_SUCCESS != dwSts)
  258. goto Ret;
  259. //
  260. // Find out if private key caching is turned on
  261. //
  262. cbData = sizeof(DWORD);
  263. dwSts = RegQueryValueEx(
  264. hKey,
  265. szKEY_CACHE_ENABLED,
  266. 0,
  267. NULL,
  268. (PBYTE) &pContInfo->fCachePrivateKeys,
  269. &cbData);
  270. if (ERROR_FILE_NOT_FOUND == dwSts)
  271. {
  272. // Reg key enabling the new behavior isn't set, so we're done.
  273. dwSts = ERROR_SUCCESS;
  274. goto Ret;
  275. }
  276. else if (ERROR_SUCCESS != dwSts || FALSE == pContInfo->fCachePrivateKeys)
  277. goto Ret;
  278. //
  279. // Find out how long to cache private keys
  280. //
  281. cbData = sizeof(DWORD);
  282. dwSts = RegQueryValueEx(
  283. hKey,
  284. szKEY_CACHE_SECONDS,
  285. 0,
  286. NULL,
  287. (PBYTE) &pContInfo->cMaxKeyLifetime,
  288. &cbData);
  289. if (ERROR_SUCCESS != dwSts)
  290. goto Ret;
  291. // Cache lifetime value stored in registry is in seconds. We'll remember
  292. // the value in milliseconds for easy comparison.
  293. pContInfo->cMaxKeyLifetime *= 1000;
  294. Ret:
  295. if (hKey)
  296. RegCloseKey(hKey);
  297. return dwSts;
  298. }
  299. /*++
  300. OpenCallerToken:
  301. This routine returns the caller's ID token.
  302. Arguments:
  303. dwFlags supplies the flags to use when opening the token.
  304. phToken receives the token. It must be closed via CloseHandle.
  305. Return Value:
  306. A DWORD status code.
  307. Remarks:
  308. Author:
  309. Doug Barlow (dbarlow) 5/2/2000
  310. --*/
  311. #undef __SUBROUTINE__
  312. #define __SUBROUTINE__ TEXT("OpenCallerToken")
  313. /*static*/ DWORD
  314. OpenCallerToken(
  315. IN DWORD dwFlags,
  316. OUT HANDLE *phToken)
  317. {
  318. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  319. DWORD dwSts;
  320. BOOL fSts;
  321. HANDLE hToken = NULL;
  322. fSts = OpenThreadToken(GetCurrentThread(), dwFlags, TRUE, &hToken);
  323. if (!fSts)
  324. {
  325. dwSts = GetLastError();
  326. if (ERROR_NO_TOKEN != dwSts)
  327. {
  328. dwReturn = dwSts;
  329. goto ErrorExit;
  330. }
  331. // For Jeff, fall back and get the process token
  332. fSts = OpenProcessToken(GetCurrentProcess(), dwFlags, &hToken);
  333. if (!fSts)
  334. {
  335. dwReturn = GetLastError();
  336. goto ErrorExit;
  337. }
  338. }
  339. *phToken = hToken;
  340. return ERROR_SUCCESS;
  341. ErrorExit:
  342. return dwReturn;
  343. }
  344. DWORD
  345. MyCryptProtectData(
  346. IN DATA_BLOB *pDataIn,
  347. IN LPCWSTR szDataDescr,
  348. IN OPTIONAL DATA_BLOB *pOptionalEntropy,
  349. IN PVOID pvReserved,
  350. IN OPTIONAL CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct,
  351. IN DWORD dwFlags,
  352. OUT DATA_BLOB *pDataOut) // out encr blob
  353. {
  354. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  355. DWORD dwRetryCount = 0;
  356. DWORD dwMilliseconds = 10;
  357. DWORD dwSts;
  358. for (;;)
  359. {
  360. if (CryptProtectData(pDataIn, szDataDescr, pOptionalEntropy,
  361. pvReserved, pPromptStruct, dwFlags, pDataOut))
  362. {
  363. break;
  364. }
  365. dwSts = GetLastError();
  366. switch (dwSts)
  367. {
  368. case RPC_S_SERVER_TOO_BUSY:
  369. if (MAX_DPAPI_RETRY_COUNT <= dwRetryCount)
  370. {
  371. dwReturn = dwSts;
  372. goto ErrorExit;
  373. }
  374. Sleep(dwMilliseconds);
  375. dwMilliseconds *= 2;
  376. dwRetryCount++;
  377. break;
  378. case RPC_S_UNKNOWN_IF: // Make this error code more friendly.
  379. dwReturn = ERROR_SERVICE_NOT_ACTIVE;
  380. goto ErrorExit;
  381. break;
  382. default:
  383. dwReturn = dwSts;
  384. goto ErrorExit;
  385. }
  386. }
  387. dwReturn = ERROR_SUCCESS;
  388. ErrorExit:
  389. return dwReturn;
  390. }
  391. DWORD
  392. MyCryptUnprotectData(
  393. IN DATA_BLOB *pDataIn, // in encr blob
  394. OUT OPTIONAL LPWSTR *ppszDataDescr, // out
  395. IN OPTIONAL DATA_BLOB *pOptionalEntropy,
  396. IN PVOID pvReserved,
  397. IN OPTIONAL CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct,
  398. IN DWORD dwFlags,
  399. OUT DATA_BLOB *pDataOut,
  400. OUT LPDWORD pdwReprotectFlags)
  401. {
  402. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  403. DWORD dwRetryCount = 0;
  404. DWORD dwMilliseconds = 10;
  405. DWORD dwSts;
  406. BOOL fSts;
  407. if (NULL != pdwReprotectFlags)
  408. {
  409. *pdwReprotectFlags = 0;
  410. dwFlags |= (CRYPTPROTECT_VERIFY_PROTECTION
  411. | CRYPTPROTECT_UI_FORBIDDEN);
  412. }
  413. for (;;)
  414. {
  415. fSts = CryptUnprotectData(pDataIn, // in encr blob
  416. ppszDataDescr, // out
  417. pOptionalEntropy,
  418. pvReserved,
  419. pPromptStruct,
  420. dwFlags,
  421. pDataOut);
  422. if (!fSts)
  423. {
  424. dwSts = GetLastError();
  425. if ((RPC_S_SERVER_TOO_BUSY == dwSts)
  426. && (MAX_DPAPI_RETRY_COUNT > dwRetryCount))
  427. {
  428. Sleep(dwMilliseconds);
  429. dwMilliseconds *= 2;
  430. dwRetryCount++;
  431. }
  432. else if ((ERROR_PASSWORD_RESTRICTION == dwSts)
  433. && (NULL != pdwReprotectFlags))
  434. {
  435. *pdwReprotectFlags |= CRYPT_USER_PROTECTED;
  436. dwFlags &= ~CRYPTPROTECT_UI_FORBIDDEN;
  437. }
  438. else
  439. {
  440. dwReturn = dwSts;
  441. break;
  442. }
  443. }
  444. else
  445. {
  446. if (NULL != pdwReprotectFlags)
  447. {
  448. dwSts = GetLastError();
  449. if (CRYPT_I_NEW_PROTECTION_REQUIRED == dwSts)
  450. *pdwReprotectFlags |= CRYPT_UPDATE_KEY;
  451. }
  452. dwReturn = ERROR_SUCCESS;
  453. break;
  454. }
  455. }
  456. return dwReturn;
  457. }
  458. void
  459. FreeEnumOldMachKeyEntries(
  460. PKEY_CONTAINER_INFO pInfo)
  461. {
  462. if (pInfo)
  463. {
  464. if (pInfo->pchEnumOldMachKeyEntries)
  465. {
  466. ContInfoFree(pInfo->pchEnumOldMachKeyEntries);
  467. pInfo->dwiOldMachKeyEntry = 0;
  468. pInfo->cMaxOldMachKeyEntry = 0;
  469. pInfo->cbOldMachKeyEntry = 0;
  470. pInfo->pchEnumOldMachKeyEntries = NULL;
  471. }
  472. }
  473. }
  474. void
  475. FreeEnumRegEntries(
  476. PKEY_CONTAINER_INFO pInfo)
  477. {
  478. if (pInfo)
  479. {
  480. if (pInfo->pchEnumRegEntries)
  481. {
  482. ContInfoFree(pInfo->pchEnumRegEntries);
  483. pInfo->dwiRegEntry = 0;
  484. pInfo->cMaxRegEntry = 0;
  485. pInfo->cbRegEntry = 0;
  486. pInfo->pchEnumRegEntries = NULL;
  487. }
  488. }
  489. }
  490. void
  491. FreeContainerInfo(
  492. PKEY_CONTAINER_INFO pInfo)
  493. {
  494. if (NULL != pInfo)
  495. {
  496. if (NULL != pInfo->pbSigPub)
  497. {
  498. ContInfoFree(pInfo->pbSigPub);
  499. pInfo->ContLens.cbSigPub = 0;
  500. pInfo->pbSigPub = NULL;
  501. }
  502. if (NULL != pInfo->pbSigEncPriv)
  503. {
  504. memnuke(pInfo->pbSigEncPriv, pInfo->ContLens.cbSigEncPriv);
  505. ContInfoFree(pInfo->pbSigEncPriv);
  506. pInfo->ContLens.cbSigEncPriv = 0;
  507. pInfo->pbSigEncPriv = NULL;
  508. }
  509. if (NULL != pInfo->pbExchPub)
  510. {
  511. ContInfoFree(pInfo->pbExchPub);
  512. pInfo->ContLens.cbExchPub = 0;
  513. pInfo->pbExchPub = NULL;
  514. }
  515. if (NULL != pInfo->pbExchEncPriv)
  516. {
  517. memnuke(pInfo->pbExchEncPriv, pInfo->ContLens.cbExchEncPriv);
  518. ContInfoFree(pInfo->pbExchEncPriv);
  519. pInfo->ContLens.cbExchEncPriv = 0;
  520. pInfo->pbExchEncPriv = NULL;
  521. }
  522. if (NULL != pInfo->pbRandom)
  523. {
  524. ContInfoFree(pInfo->pbRandom);
  525. pInfo->ContLens.cbRandom = 0;
  526. pInfo->pbRandom = NULL;
  527. }
  528. if (NULL != pInfo->pszUserName)
  529. {
  530. ContInfoFree(pInfo->pszUserName);
  531. pInfo->ContLens.cbName = 0;
  532. pInfo->pszUserName = NULL;
  533. }
  534. FreeEnumOldMachKeyEntries(pInfo);
  535. FreeEnumRegEntries(pInfo);
  536. if (NULL != pInfo->hFind)
  537. FindClose(pInfo->hFind);
  538. }
  539. }
  540. /*static*/ DWORD
  541. GetHashOfContainer(
  542. LPCSTR pszContainer,
  543. LPWSTR pszHash)
  544. {
  545. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  546. MD5_CTX MD5;
  547. LPSTR pszLowerContainer = NULL;
  548. DWORD *pdw1;
  549. DWORD *pdw2;
  550. DWORD *pdw3;
  551. DWORD *pdw4;
  552. pszLowerContainer = (LPSTR)ContInfoAlloc(
  553. strlen(pszContainer) + sizeof(CHAR));
  554. if (NULL == pszLowerContainer)
  555. {
  556. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  557. goto ErrorExit;
  558. }
  559. lstrcpy(pszLowerContainer, pszContainer);
  560. _strlwr(pszLowerContainer);
  561. MD5Init(&MD5);
  562. MD5Update(&MD5,
  563. (LPBYTE)pszLowerContainer,
  564. strlen(pszLowerContainer) + sizeof(CHAR));
  565. MD5Final(&MD5);
  566. pdw1 = (DWORD*)&MD5.digest[0];
  567. pdw2 = (DWORD*)&MD5.digest[4];
  568. pdw3 = (DWORD*)&MD5.digest[8];
  569. pdw4 = (DWORD*)&MD5.digest[12];
  570. wsprintfW(pszHash, L"%08hx%08hx%08hx%08hx", *pdw1, *pdw2, *pdw3, *pdw4);
  571. dwReturn = ERROR_SUCCESS;
  572. ErrorExit:
  573. if (NULL != pszLowerContainer)
  574. ContInfoFree(pszLowerContainer);
  575. return dwReturn;
  576. }
  577. /*static*/ DWORD
  578. GetMachineGUID(
  579. LPWSTR *ppwszUuid)
  580. {
  581. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  582. HKEY hRegKey = 0;
  583. LPSTR pszUuid = NULL;
  584. LPWSTR pwszUuid = NULL;
  585. DWORD cbUuid = sizeof(UUID);
  586. DWORD cch = 0;
  587. DWORD dwSts;
  588. *ppwszUuid = NULL;
  589. // read the GUID from the Local Machine portion of the registry
  590. dwSts = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SZLOCALMACHINECRYPTO,
  591. 0, KEY_READ | KEY_WOW64_64KEY, &hRegKey);
  592. if (ERROR_FILE_NOT_FOUND == dwSts)
  593. {
  594. dwReturn = ERROR_SUCCESS;
  595. goto ErrorExit; // Return a success code, but a null GUID.
  596. }
  597. else if (ERROR_SUCCESS != dwSts)
  598. {
  599. dwReturn = dwSts; // (DWORD)NTE_FAIL
  600. goto ErrorExit;
  601. }
  602. dwSts = RegQueryValueEx(hRegKey, SZCRYPTOMACHINEGUID,
  603. 0, NULL, NULL, &cbUuid);
  604. if (ERROR_FILE_NOT_FOUND == dwSts)
  605. {
  606. dwReturn = ERROR_SUCCESS;
  607. goto ErrorExit; // Return a success code, but a null GUID.
  608. }
  609. else if (ERROR_SUCCESS != dwSts)
  610. {
  611. dwReturn = dwSts; // (DWORD)NTE_FAIL
  612. goto ErrorExit;
  613. }
  614. pszUuid = (LPSTR)ContInfoAlloc(cbUuid);
  615. if (NULL == pszUuid)
  616. {
  617. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  618. goto ErrorExit;
  619. }
  620. dwSts = RegQueryValueEx(hRegKey, SZCRYPTOMACHINEGUID,
  621. 0, NULL, (LPBYTE)pszUuid, &cbUuid);
  622. if (ERROR_SUCCESS != dwSts)
  623. {
  624. dwReturn = dwSts; // (DWORD)NTE_FAIL;
  625. goto ErrorExit;
  626. }
  627. // convert from ansi to unicode
  628. cch = MultiByteToWideChar(CP_ACP, MB_COMPOSITE, pszUuid, -1, NULL, cch);
  629. if (0 == cch)
  630. {
  631. dwReturn = GetLastError();
  632. goto ErrorExit;
  633. }
  634. pwszUuid = ContInfoAlloc((cch + 1) * sizeof(WCHAR));
  635. if (NULL == pwszUuid)
  636. {
  637. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  638. goto ErrorExit;
  639. }
  640. cch = MultiByteToWideChar(CP_ACP, MB_COMPOSITE, pszUuid, -1,
  641. pwszUuid, cch);
  642. if (0 == cch)
  643. {
  644. dwReturn = GetLastError();
  645. goto ErrorExit;
  646. }
  647. *ppwszUuid = pwszUuid;
  648. pwszUuid = NULL;
  649. dwReturn = ERROR_SUCCESS;
  650. ErrorExit:
  651. if (NULL != pwszUuid)
  652. ContInfoFree(pwszUuid);
  653. if (NULL != pszUuid)
  654. ContInfoFree(pszUuid);
  655. if (NULL != hRegKey)
  656. RegCloseKey(hRegKey);
  657. return dwReturn;
  658. }
  659. DWORD
  660. SetMachineGUID(
  661. void)
  662. {
  663. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  664. HKEY hRegKey = 0;
  665. UUID Uuid;
  666. LPSTR pszUuid = NULL;
  667. DWORD cbUuid;
  668. LPWSTR pwszOldUuid = NULL;
  669. DWORD dwSts;
  670. DWORD dwResult;
  671. dwSts = GetMachineGUID(&pwszOldUuid);
  672. if (ERROR_SUCCESS != dwSts)
  673. {
  674. dwReturn = dwSts;
  675. goto ErrorExit;
  676. }
  677. if (NULL != pwszOldUuid)
  678. {
  679. dwReturn = (DWORD)NTE_FAIL;
  680. goto ErrorExit;
  681. }
  682. UuidCreate(&Uuid);
  683. dwSts = (DWORD) UuidToStringA(&Uuid, &pszUuid);
  684. if (RPC_S_OK != dwSts)
  685. {
  686. dwReturn = dwSts; // (DWORD)NTE_FAIL;
  687. goto ErrorExit;
  688. }
  689. // read the GUID from the Local Machine portion of the registry
  690. dwSts = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  691. SZLOCALMACHINECRYPTO,
  692. 0, NULL, REG_OPTION_NON_VOLATILE,
  693. KEY_ALL_ACCESS | KEY_WOW64_64KEY, NULL, &hRegKey,
  694. &dwResult);
  695. if (ERROR_SUCCESS != dwSts)
  696. {
  697. dwReturn = dwSts; // (DWORD)NTE_FAIL;
  698. goto ErrorExit;
  699. }
  700. dwSts = RegQueryValueEx(hRegKey, SZCRYPTOMACHINEGUID,
  701. 0, NULL, NULL,
  702. &cbUuid);
  703. if (ERROR_FILE_NOT_FOUND != dwSts)
  704. {
  705. dwReturn = (DWORD)NTE_FAIL;
  706. goto ErrorExit;
  707. }
  708. dwSts = RegSetValueEx(hRegKey, SZCRYPTOMACHINEGUID,
  709. 0, REG_SZ, (BYTE*)pszUuid,
  710. strlen(pszUuid) + 1);
  711. if (ERROR_SUCCESS != dwSts)
  712. {
  713. dwReturn = dwSts; // (DWORD)NTE_FAIL;
  714. goto ErrorExit;
  715. }
  716. dwReturn = ERROR_SUCCESS;
  717. ErrorExit:
  718. if (pszUuid)
  719. RpcStringFreeA(&pszUuid);
  720. if (pwszOldUuid)
  721. ContInfoFree(pwszOldUuid);
  722. if (hRegKey)
  723. RegCloseKey(hRegKey);
  724. return dwReturn;
  725. }
  726. /*static*/ DWORD
  727. AddMachineGuidToContainerName(
  728. LPSTR pszContainer,
  729. LPWSTR pwszNewContainer)
  730. {
  731. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  732. WCHAR rgwszHash[33];
  733. LPWSTR pwszUuid = NULL;
  734. DWORD dwSts;
  735. memset(rgwszHash, 0, sizeof(rgwszHash));
  736. // get the stringized hash of the container name
  737. dwSts = GetHashOfContainer(pszContainer, rgwszHash);
  738. if (ERROR_SUCCESS != dwSts)
  739. {
  740. dwReturn = dwSts;
  741. goto ErrorExit;
  742. }
  743. // get the GUID of the machine
  744. dwSts = GetMachineGUID(&pwszUuid);
  745. if (ERROR_SUCCESS != dwSts)
  746. {
  747. dwReturn = dwSts;
  748. goto ErrorExit;
  749. }
  750. if (NULL == pwszUuid)
  751. {
  752. dwReturn = (DWORD)NTE_FAIL;
  753. goto ErrorExit;
  754. }
  755. wcscpy(pwszNewContainer, rgwszHash);
  756. wcscat(pwszNewContainer, L"_");
  757. wcscat(pwszNewContainer, pwszUuid);
  758. dwReturn = ERROR_SUCCESS;
  759. ErrorExit:
  760. if (pwszUuid)
  761. ContInfoFree(pwszUuid);
  762. return dwReturn;
  763. }
  764. //
  765. // Just tries to use DPAPI to make sure it works before creating a key
  766. // container.
  767. //
  768. DWORD
  769. TryDPAPI(
  770. void)
  771. {
  772. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  773. CRYPTPROTECT_PROMPTSTRUCT PromptStruct;
  774. CRYPT_DATA_BLOB DataIn;
  775. CRYPT_DATA_BLOB DataOut;
  776. CRYPT_DATA_BLOB ExtraEntropy;
  777. DWORD dwJunk = 0;
  778. DWORD dwSts;
  779. memset(&PromptStruct, 0, sizeof(PromptStruct));
  780. memset(&DataIn, 0, sizeof(DataIn));
  781. memset(&DataOut, 0, sizeof(DataOut));
  782. PromptStruct.cbSize = sizeof(PromptStruct);
  783. DataIn.cbData = sizeof(DWORD);
  784. DataIn.pbData = (BYTE*)&dwJunk;
  785. ExtraEntropy.cbData = sizeof(STUFF_TO_GO_INTO_MIX);
  786. ExtraEntropy.pbData = (LPBYTE)STUFF_TO_GO_INTO_MIX;
  787. dwSts = MyCryptProtectData(&DataIn, L"Export Flag", &ExtraEntropy, NULL,
  788. &PromptStruct, 0, &DataOut);
  789. if (ERROR_SUCCESS != dwSts)
  790. {
  791. dwReturn = dwSts;
  792. goto ErrorExit;
  793. }
  794. dwReturn = ERROR_SUCCESS;
  795. ErrorExit:
  796. if (NULL != DataOut.pbData)
  797. LocalFree(DataOut.pbData);
  798. return dwReturn;
  799. }
  800. /*static*/ DWORD
  801. ProtectExportabilityFlag(
  802. IN BOOL fExportable,
  803. IN BOOL fMachineKeyset,
  804. OUT BYTE **ppbProtectedExportability,
  805. OUT DWORD *pcbProtectedExportability)
  806. {
  807. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  808. CRYPTPROTECT_PROMPTSTRUCT PromptStruct;
  809. CRYPT_DATA_BLOB DataIn;
  810. CRYPT_DATA_BLOB DataOut;
  811. CRYPT_DATA_BLOB ExtraEntropy;
  812. DWORD dwProtectFlags = 0;
  813. DWORD dwSts = 0;
  814. memset(&PromptStruct, 0, sizeof(PromptStruct));
  815. memset(&DataIn, 0, sizeof(DataIn));
  816. memset(&DataOut, 0, sizeof(DataOut));
  817. if (fMachineKeyset)
  818. dwProtectFlags = CRYPTPROTECT_LOCAL_MACHINE;
  819. PromptStruct.cbSize = sizeof(PromptStruct);
  820. DataIn.cbData = sizeof(BOOL);
  821. DataIn.pbData = (BYTE*)&fExportable;
  822. ExtraEntropy.cbData = sizeof(STUFF_TO_GO_INTO_MIX);
  823. ExtraEntropy.pbData = (LPBYTE)STUFF_TO_GO_INTO_MIX;
  824. dwSts = MyCryptProtectData(&DataIn, L"Export Flag", &ExtraEntropy, NULL,
  825. &PromptStruct, dwProtectFlags, &DataOut);
  826. if (ERROR_SUCCESS != dwSts)
  827. {
  828. dwReturn = dwSts;
  829. goto ErrorExit;
  830. }
  831. *ppbProtectedExportability = ContInfoAlloc(DataOut.cbData);
  832. if (NULL == *ppbProtectedExportability)
  833. {
  834. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  835. goto ErrorExit;
  836. }
  837. *pcbProtectedExportability = DataOut.cbData;
  838. memcpy(*ppbProtectedExportability, DataOut.pbData, DataOut.cbData);
  839. dwReturn = ERROR_SUCCESS;
  840. ErrorExit:
  841. if (NULL != DataOut.pbData)
  842. LocalFree(DataOut.pbData);
  843. return dwReturn;
  844. }
  845. /*static*/ DWORD
  846. UnprotectExportabilityFlag(
  847. IN BOOL fMachineKeyset,
  848. IN BYTE *pbProtectedExportability,
  849. IN DWORD cbProtectedExportability,
  850. IN BOOL *pfExportable)
  851. {
  852. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  853. CRYPTPROTECT_PROMPTSTRUCT PromptStruct;
  854. CRYPT_DATA_BLOB DataIn;
  855. CRYPT_DATA_BLOB DataOut;
  856. CRYPT_DATA_BLOB ExtraEntropy;
  857. DWORD dwProtectFlags = 0;
  858. DWORD dwSts = 0;
  859. memset(&PromptStruct, 0, sizeof(PromptStruct));
  860. memset(&DataIn, 0, sizeof(DataIn));
  861. memset(&DataOut, 0, sizeof(DataOut));
  862. memset(&ExtraEntropy, 0, sizeof(ExtraEntropy));
  863. if (fMachineKeyset)
  864. dwProtectFlags = CRYPTPROTECT_LOCAL_MACHINE;
  865. PromptStruct.cbSize = sizeof(PromptStruct);
  866. DataIn.cbData = cbProtectedExportability;
  867. DataIn.pbData = pbProtectedExportability;
  868. ExtraEntropy.cbData = sizeof(STUFF_TO_GO_INTO_MIX);
  869. ExtraEntropy.pbData = (LPBYTE)STUFF_TO_GO_INTO_MIX;
  870. dwSts = MyCryptUnprotectData(&DataIn, NULL, &ExtraEntropy, NULL,
  871. &PromptStruct, dwProtectFlags, &DataOut,
  872. NULL);
  873. if (ERROR_SUCCESS != dwSts)
  874. {
  875. dwReturn = dwSts; // NTE_BAD_KEYSET
  876. goto ErrorExit;
  877. }
  878. if (sizeof(BOOL) != DataOut.cbData)
  879. {
  880. dwReturn = (DWORD)NTE_BAD_KEYSET;
  881. goto ErrorExit;
  882. }
  883. *pfExportable = *((BOOL*)DataOut.pbData);
  884. dwReturn = ERROR_SUCCESS;
  885. ErrorExit:
  886. // free the DataOut struct if necessary
  887. if (NULL != DataOut.pbData)
  888. LocalFree(DataOut.pbData);
  889. return dwReturn;
  890. }
  891. /*++
  892. Creates a DACL for the MachineKeys directory for
  893. machine keysets so that Everyone may create machine keys.
  894. --*/
  895. /*static*/ DWORD
  896. GetMachineKeysetDirDACL(
  897. IN OUT PACL *ppDacl)
  898. {
  899. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  900. SID_IDENTIFIER_AUTHORITY siaWorld = SECURITY_WORLD_SID_AUTHORITY;
  901. SID_IDENTIFIER_AUTHORITY siaNTAuth = SECURITY_NT_AUTHORITY;
  902. PSID pEveryoneSid = NULL;
  903. PSID pAdminsSid = NULL;
  904. DWORD dwAclSize;
  905. //
  906. // prepare Sids representing the world and admins
  907. //
  908. if (!AllocateAndInitializeSid(&siaWorld,
  909. 1,
  910. SECURITY_WORLD_RID,
  911. 0, 0, 0, 0, 0, 0, 0,
  912. &pEveryoneSid))
  913. {
  914. dwReturn = GetLastError();
  915. goto ErrorExit;
  916. }
  917. if (!AllocateAndInitializeSid(&siaNTAuth,
  918. 2,
  919. SECURITY_BUILTIN_DOMAIN_RID,
  920. DOMAIN_ALIAS_RID_ADMINS,
  921. 0, 0, 0, 0, 0, 0,
  922. &pAdminsSid))
  923. {
  924. dwReturn = GetLastError();
  925. goto ErrorExit;
  926. }
  927. //
  928. // compute size of new acl
  929. //
  930. dwAclSize = sizeof(ACL)
  931. + 2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD))
  932. + GetLengthSid(pEveryoneSid)
  933. + GetLengthSid(pAdminsSid);
  934. //
  935. // allocate storage for Acl
  936. //
  937. *ppDacl = (PACL)ContInfoAlloc(dwAclSize);
  938. if (NULL == *ppDacl)
  939. {
  940. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  941. goto ErrorExit;
  942. }
  943. if (!InitializeAcl(*ppDacl, dwAclSize, ACL_REVISION))
  944. {
  945. dwReturn = GetLastError();
  946. goto ErrorExit;
  947. }
  948. if (!AddAccessAllowedAce(*ppDacl,
  949. ACL_REVISION,
  950. (FILE_GENERIC_WRITE | FILE_GENERIC_READ) & (~WRITE_DAC),
  951. pEveryoneSid))
  952. {
  953. dwReturn = GetLastError();
  954. goto ErrorExit;
  955. }
  956. if (!AddAccessAllowedAce(*ppDacl,
  957. ACL_REVISION,
  958. FILE_ALL_ACCESS,
  959. pAdminsSid))
  960. {
  961. dwReturn = GetLastError();
  962. goto ErrorExit;
  963. }
  964. dwReturn = ERROR_SUCCESS;
  965. ErrorExit:
  966. if (NULL != pEveryoneSid)
  967. FreeSid(pEveryoneSid);
  968. if (NULL != pAdminsSid)
  969. FreeSid(pAdminsSid);
  970. return dwReturn;
  971. }
  972. DWORD
  973. CreateSystemDirectory(
  974. LPCWSTR lpPathName,
  975. SECURITY_ATTRIBUTES *pSecAttrib)
  976. {
  977. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  978. NTSTATUS Status;
  979. OBJECT_ATTRIBUTES Obja;
  980. HANDLE Handle;
  981. UNICODE_STRING FileName;
  982. IO_STATUS_BLOCK IoStatusBlock;
  983. RTL_RELATIVE_NAME RelativeName;
  984. PVOID FreeBuffer;
  985. if(!RtlDosPathNameToNtPathName_U( lpPathName,
  986. &FileName,
  987. NULL,
  988. &RelativeName))
  989. {
  990. dwReturn = ERROR_PATH_NOT_FOUND;
  991. goto ErrorExit;
  992. }
  993. FreeBuffer = FileName.Buffer;
  994. if ( RelativeName.RelativeName.Length )
  995. {
  996. FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
  997. }
  998. else
  999. {
  1000. RelativeName.ContainingDirectory = NULL;
  1001. }
  1002. InitializeObjectAttributes( &Obja,
  1003. &FileName,
  1004. OBJ_CASE_INSENSITIVE,
  1005. RelativeName.ContainingDirectory,
  1006. (NULL != pSecAttrib)
  1007. ? pSecAttrib->lpSecurityDescriptor
  1008. : NULL);
  1009. // Creating the directory with attribute FILE_ATTRIBUTE_SYSTEM to avoid inheriting encryption
  1010. // property from parent directory
  1011. Status = NtCreateFile( &Handle,
  1012. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  1013. &Obja,
  1014. &IoStatusBlock,
  1015. NULL,
  1016. FILE_ATTRIBUTE_SYSTEM,
  1017. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1018. FILE_CREATE,
  1019. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
  1020. NULL,
  1021. 0L );
  1022. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  1023. if(NT_SUCCESS(Status))
  1024. {
  1025. NtClose(Handle);
  1026. dwReturn = ERROR_SUCCESS;
  1027. }
  1028. else
  1029. {
  1030. if (STATUS_TIMEOUT == Status)
  1031. dwReturn = ERROR_TIMEOUT;
  1032. else
  1033. dwReturn = RtlNtStatusToDosError(Status);
  1034. }
  1035. ErrorExit:
  1036. return dwReturn;
  1037. }
  1038. /*++
  1039. Create all subdirectories if they do not exists starting at
  1040. szCreationStartPoint.
  1041. szCreationStartPoint must point to a character within the null terminated
  1042. buffer specified by the szFullPath parameter.
  1043. Note that szCreationStartPoint should not point at the first character
  1044. of a drive root, eg:
  1045. d:\foo\bar\bilge\water
  1046. \\server\share\foo\bar
  1047. \\?\d:\big\path\bilge\water
  1048. Instead, szCreationStartPoint should point beyond these components, eg:
  1049. bar\bilge\water
  1050. foo\bar
  1051. big\path\bilge\water
  1052. This function does not implement logic for adjusting to compensate for
  1053. these inputs because the environment it was design to be used in causes
  1054. the input szCreationStartPoint to point well into the szFullPath input
  1055. buffer.
  1056. --*/
  1057. /*static*/ DWORD
  1058. CreateNestedDirectories(
  1059. IN LPWSTR wszFullPath,
  1060. IN LPWSTR wszCreationStartPoint, // must point in null-terminated range of szFullPath
  1061. IN BOOL fMachineKeyset)
  1062. {
  1063. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  1064. DWORD i;
  1065. DWORD dwPrevious = 0;
  1066. DWORD cchRemaining;
  1067. SECURITY_ATTRIBUTES SecAttrib;
  1068. SECURITY_ATTRIBUTES *pSecAttrib;
  1069. SECURITY_DESCRIPTOR sd;
  1070. PACL pDacl = NULL;
  1071. DWORD dwSts = ERROR_SUCCESS;
  1072. BOOL fSts;
  1073. if (wszCreationStartPoint < wszFullPath ||
  1074. wszCreationStartPoint > (wcslen(wszFullPath) + wszFullPath))
  1075. {
  1076. dwReturn = ERROR_INVALID_PARAMETER;
  1077. goto ErrorExit;
  1078. }
  1079. cchRemaining = wcslen(wszCreationStartPoint);
  1080. //
  1081. // scan from left to right in the szCreationStartPoint string
  1082. // looking for directory delimiter.
  1083. //
  1084. for (i = 0; i < cchRemaining; i++)
  1085. {
  1086. WCHAR charReplaced = wszCreationStartPoint[i];
  1087. if (charReplaced == '\\' || charReplaced == '/')
  1088. {
  1089. wszCreationStartPoint[ i ] = '\0';
  1090. pSecAttrib = NULL;
  1091. if (fMachineKeyset)
  1092. {
  1093. memset(&SecAttrib, 0, sizeof(SecAttrib));
  1094. SecAttrib.nLength = sizeof(SecAttrib);
  1095. if (0 == wcscmp(MACHINE_KEYS_DIR,
  1096. &(wszCreationStartPoint[ dwPrevious ])))
  1097. {
  1098. dwSts = GetMachineKeysetDirDACL(&pDacl);
  1099. if (ERROR_SUCCESS != dwSts)
  1100. {
  1101. dwReturn = dwSts;
  1102. goto ErrorExit;
  1103. }
  1104. fSts = InitializeSecurityDescriptor(&sd,
  1105. SECURITY_DESCRIPTOR_REVISION);
  1106. if (!fSts)
  1107. {
  1108. dwReturn = GetLastError();
  1109. goto ErrorExit;
  1110. }
  1111. fSts = SetSecurityDescriptorDacl(&sd, TRUE, pDacl, FALSE);
  1112. if (!fSts)
  1113. {
  1114. dwReturn = GetLastError();
  1115. goto ErrorExit;
  1116. }
  1117. SecAttrib.lpSecurityDescriptor = &sd;
  1118. pSecAttrib = &SecAttrib;
  1119. }
  1120. }
  1121. dwSts = CreateSystemDirectory(wszFullPath, pSecAttrib);
  1122. dwPrevious = i + 1;
  1123. wszCreationStartPoint[ i ] = charReplaced;
  1124. if (ERROR_SUCCESS != dwSts)
  1125. {
  1126. //
  1127. // continue onwards, trying to create specified
  1128. // subdirectories. This is done to address the obscure
  1129. // scenario where the Bypass Traverse Checking Privilege
  1130. // allows the caller to create directories below an
  1131. // existing path where one component denies the user
  1132. // access. We just keep trying and the last
  1133. // CreateDirectory() result is returned to the caller.
  1134. //
  1135. continue;
  1136. }
  1137. }
  1138. }
  1139. if (ERROR_ALREADY_EXISTS == dwSts)
  1140. dwSts = ERROR_SUCCESS;
  1141. dwReturn = dwSts;
  1142. ErrorExit:
  1143. if (NULL != pDacl)
  1144. ContInfoFree(pDacl);
  1145. return dwReturn;
  1146. }
  1147. #ifdef _M_IX86
  1148. BOOL WINAPI
  1149. FIsWinNT(
  1150. void)
  1151. {
  1152. static BOOL fIKnow = FALSE;
  1153. static BOOL fIsWinNT = FALSE;
  1154. OSVERSIONINFO osVer;
  1155. if (fIKnow)
  1156. return(fIsWinNT);
  1157. memset(&osVer, 0, sizeof(OSVERSIONINFO));
  1158. osVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1159. if (GetVersionEx(&osVer))
  1160. fIsWinNT = (osVer.dwPlatformId == VER_PLATFORM_WIN32_NT);
  1161. // even on an error, this is as good as it gets
  1162. fIKnow = TRUE;
  1163. return fIsWinNT;
  1164. }
  1165. #else // other than _M_IX86
  1166. BOOL WINAPI
  1167. FIsWinNT(
  1168. void)
  1169. {
  1170. return TRUE;
  1171. }
  1172. #endif // _M_IX86
  1173. /*++
  1174. This function determines if the user associated with the
  1175. specified token is the Local System account.
  1176. --*/
  1177. DWORD
  1178. IsLocalSystem(
  1179. BOOL *pfIsLocalSystem)
  1180. {
  1181. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  1182. HANDLE hToken = 0;
  1183. HANDLE hThreadToken = NULL;
  1184. UCHAR InfoBuffer[1024];
  1185. DWORD dwInfoBufferSize = sizeof(InfoBuffer);
  1186. PTOKEN_USER SlowBuffer = NULL;
  1187. PTOKEN_USER pTokenUser = (PTOKEN_USER)InfoBuffer;
  1188. PSID psidLocalSystem = NULL;
  1189. SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
  1190. BOOL fSts;
  1191. DWORD dwSts;
  1192. *pfIsLocalSystem = FALSE;
  1193. fSts = OpenThreadToken(GetCurrentThread(),
  1194. MAXIMUM_ALLOWED,
  1195. TRUE,
  1196. &hThreadToken);
  1197. if (fSts)
  1198. {
  1199. // impersonation is going on need to save handle
  1200. RevertToSelf();
  1201. }
  1202. fSts = OpenProcessToken(GetCurrentProcess(),
  1203. TOKEN_QUERY,
  1204. &hToken);
  1205. if (!fSts)
  1206. {
  1207. dwReturn = GetLastError();
  1208. goto ErrorExit;
  1209. }
  1210. if (NULL != hThreadToken)
  1211. {
  1212. // put the impersonation token back
  1213. fSts = SetThreadToken(NULL, hThreadToken);
  1214. if (!fSts)
  1215. {
  1216. dwReturn = GetLastError();
  1217. goto ErrorExit;
  1218. }
  1219. }
  1220. fSts = GetTokenInformation(hToken, TokenUser, pTokenUser,
  1221. dwInfoBufferSize, &dwInfoBufferSize);
  1222. if (!fSts)
  1223. {
  1224. dwSts = GetLastError();
  1225. if (ERROR_INSUFFICIENT_BUFFER == dwSts)
  1226. {
  1227. //
  1228. // if fast buffer wasn't big enough, allocate enough storage
  1229. // and try again.
  1230. //
  1231. SlowBuffer = (PTOKEN_USER)ContInfoAlloc(dwInfoBufferSize);
  1232. if (NULL == SlowBuffer)
  1233. {
  1234. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  1235. goto ErrorExit;
  1236. }
  1237. pTokenUser = SlowBuffer;
  1238. fSts = GetTokenInformation(hToken, TokenUser, pTokenUser,
  1239. dwInfoBufferSize,
  1240. &dwInfoBufferSize);
  1241. if (!fSts)
  1242. {
  1243. dwReturn = GetLastError();
  1244. goto ErrorExit;
  1245. }
  1246. }
  1247. else
  1248. {
  1249. dwReturn = dwSts;
  1250. goto ErrorExit;
  1251. }
  1252. }
  1253. fSts = AllocateAndInitializeSid(&siaNtAuthority,
  1254. 1,
  1255. SECURITY_LOCAL_SYSTEM_RID,
  1256. 0, 0, 0, 0, 0, 0, 0,
  1257. &psidLocalSystem);
  1258. if (!fSts)
  1259. {
  1260. dwReturn = GetLastError();
  1261. goto ErrorExit;
  1262. }
  1263. if (EqualSid(psidLocalSystem, pTokenUser->User.Sid))
  1264. *pfIsLocalSystem = TRUE;
  1265. dwReturn = ERROR_SUCCESS;
  1266. ErrorExit:
  1267. if (NULL != SlowBuffer)
  1268. ContInfoFree(SlowBuffer);
  1269. if (NULL != psidLocalSystem)
  1270. FreeSid(psidLocalSystem);
  1271. if (NULL != hThreadToken)
  1272. CloseHandle(hThreadToken);
  1273. if (NULL != hToken)
  1274. CloseHandle(hToken);
  1275. return dwReturn;
  1276. }
  1277. /*++
  1278. This function determines if the user associated with the
  1279. specified token is the Local System account.
  1280. --*/
  1281. /*static*/ DWORD
  1282. IsThreadLocalSystem(
  1283. BOOL *pfIsLocalSystem)
  1284. {
  1285. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  1286. BOOL fSts;
  1287. DWORD dwSts;
  1288. HANDLE hToken = 0;
  1289. UCHAR InfoBuffer[1024];
  1290. DWORD dwInfoBufferSize = sizeof(InfoBuffer);
  1291. PTOKEN_USER SlowBuffer = NULL;
  1292. PTOKEN_USER pTokenUser = (PTOKEN_USER)InfoBuffer;
  1293. PSID psidLocalSystem = NULL;
  1294. SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
  1295. *pfIsLocalSystem = FALSE;
  1296. dwSts = OpenCallerToken(TOKEN_QUERY, &hToken);
  1297. if (ERROR_SUCCESS != dwSts)
  1298. {
  1299. dwReturn = dwSts;
  1300. goto ErrorExit;
  1301. }
  1302. fSts = GetTokenInformation(hToken, TokenUser, pTokenUser,
  1303. dwInfoBufferSize, &dwInfoBufferSize);
  1304. //
  1305. // if fast buffer wasn't big enough, allocate enough storage
  1306. // and try again.
  1307. //
  1308. if (!fSts)
  1309. {
  1310. dwSts = GetLastError();
  1311. if (ERROR_INSUFFICIENT_BUFFER != dwSts)
  1312. {
  1313. dwReturn = dwSts;
  1314. goto ErrorExit;
  1315. }
  1316. SlowBuffer = (PTOKEN_USER)ContInfoAlloc(dwInfoBufferSize);
  1317. if (NULL == SlowBuffer)
  1318. {
  1319. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  1320. goto ErrorExit;
  1321. }
  1322. pTokenUser = SlowBuffer;
  1323. fSts = GetTokenInformation(hToken, TokenUser, pTokenUser,
  1324. dwInfoBufferSize, &dwInfoBufferSize);
  1325. if (!fSts)
  1326. {
  1327. dwReturn = GetLastError();
  1328. goto ErrorExit;
  1329. }
  1330. }
  1331. fSts = AllocateAndInitializeSid(&siaNtAuthority,
  1332. 1,
  1333. SECURITY_LOCAL_SYSTEM_RID,
  1334. 0, 0, 0, 0, 0, 0, 0,
  1335. &psidLocalSystem);
  1336. if (!fSts)
  1337. {
  1338. dwReturn = GetLastError();
  1339. goto ErrorExit;
  1340. }
  1341. if (EqualSid(psidLocalSystem, pTokenUser->User.Sid))
  1342. *pfIsLocalSystem = TRUE;
  1343. dwReturn = ERROR_SUCCESS;
  1344. ErrorExit:
  1345. if (NULL != SlowBuffer)
  1346. ContInfoFree(SlowBuffer);
  1347. if (NULL != psidLocalSystem)
  1348. FreeSid(psidLocalSystem);
  1349. if (NULL != hToken)
  1350. CloseHandle(hToken);
  1351. return dwReturn;
  1352. }
  1353. /*static*/ DWORD
  1354. GetTextualSidA(
  1355. PSID pSid, // binary Sid
  1356. LPSTR TextualSid, // buffer for Textual representaion of Sid
  1357. LPDWORD dwBufferLen) // required/provided TextualSid buffersize
  1358. {
  1359. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  1360. BOOL fSts;
  1361. PSID_IDENTIFIER_AUTHORITY psia;
  1362. DWORD dwSubAuthorities;
  1363. DWORD dwCounter;
  1364. DWORD dwSidSize;
  1365. fSts = IsValidSid(pSid);
  1366. if (!fSts)
  1367. {
  1368. dwReturn = ERROR_INVALID_PARAMETER;
  1369. goto ErrorExit;
  1370. }
  1371. // obtain SidIdentifierAuthority
  1372. psia = GetSidIdentifierAuthority(pSid);
  1373. // obtain sidsubauthority count
  1374. dwSubAuthorities = *GetSidSubAuthorityCount(pSid);
  1375. //
  1376. // compute buffer length (conservative guess)
  1377. // S-SID_REVISION- + identifierauthority- + subauthorities- + NULL
  1378. dwSidSize = (15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(WCHAR);
  1379. //
  1380. // check provided buffer length.
  1381. // If not large enough, indicate proper size and setlasterror
  1382. if (*dwBufferLen < dwSidSize)
  1383. {
  1384. *dwBufferLen = dwSidSize;
  1385. dwReturn = ERROR_INSUFFICIENT_BUFFER;
  1386. goto ErrorExit;
  1387. }
  1388. //
  1389. // prepare S-SID_REVISION-
  1390. dwSidSize = wsprintfA(TextualSid, "S-%lu-", SID_REVISION );
  1391. //
  1392. // prepare SidIdentifierAuthority
  1393. if ((psia->Value[0] != 0) || (psia->Value[1] != 0))
  1394. {
  1395. dwSidSize += wsprintfA(TextualSid + dwSidSize,
  1396. "0x%02hx%02hx%02hx%02hx%02hx%02hx",
  1397. (USHORT)psia->Value[0],
  1398. (USHORT)psia->Value[1],
  1399. (USHORT)psia->Value[2],
  1400. (USHORT)psia->Value[3],
  1401. (USHORT)psia->Value[4],
  1402. (USHORT)psia->Value[5]);
  1403. }
  1404. else
  1405. {
  1406. dwSidSize += wsprintfA(TextualSid + dwSidSize,
  1407. "%lu",
  1408. (ULONG)(psia->Value[5])
  1409. + (ULONG)(psia->Value[4] << 8)
  1410. + (ULONG)(psia->Value[3] << 16)
  1411. + (ULONG)(psia->Value[2] << 24));
  1412. }
  1413. //
  1414. // loop through SidSubAuthorities
  1415. for (dwCounter = 0; dwCounter < dwSubAuthorities; dwCounter++)
  1416. {
  1417. dwSidSize += wsprintfA(TextualSid + dwSidSize,
  1418. "-%lu",
  1419. *GetSidSubAuthority(pSid, dwCounter));
  1420. }
  1421. *dwBufferLen = dwSidSize + 1; // tell caller how many chars (include NULL)
  1422. dwReturn = ERROR_SUCCESS;
  1423. ErrorExit:
  1424. return dwReturn;
  1425. }
  1426. /*static*/ DWORD
  1427. GetTextualSidW(
  1428. PSID pSid, // binary Sid
  1429. LPWSTR wszTextualSid, // buffer for Textual representaion of Sid
  1430. LPDWORD dwBufferLen) // required/provided TextualSid buffersize
  1431. {
  1432. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  1433. BOOL fSts;
  1434. PSID_IDENTIFIER_AUTHORITY psia;
  1435. DWORD dwSubAuthorities;
  1436. DWORD dwCounter;
  1437. DWORD dwSidSize;
  1438. fSts = IsValidSid(pSid);
  1439. if (!fSts)
  1440. {
  1441. dwReturn = ERROR_INVALID_PARAMETER;
  1442. goto ErrorExit;
  1443. }
  1444. // obtain SidIdentifierAuthority
  1445. psia = GetSidIdentifierAuthority(pSid);
  1446. // obtain sidsubauthority count
  1447. dwSubAuthorities = *GetSidSubAuthorityCount(pSid);
  1448. //
  1449. // compute buffer length (conservative guess)
  1450. // S-SID_REVISION- + identifierauthority- + subauthorities- + NULL
  1451. dwSidSize = (15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(WCHAR);
  1452. //
  1453. // check provided buffer length.
  1454. // If not large enough, indicate proper size and setlasterror
  1455. if (*dwBufferLen < dwSidSize)
  1456. {
  1457. *dwBufferLen = dwSidSize;
  1458. dwReturn = ERROR_INSUFFICIENT_BUFFER;
  1459. goto ErrorExit;
  1460. }
  1461. //
  1462. // prepare S-SID_REVISION-
  1463. dwSidSize = wsprintfW(wszTextualSid, L"S-%lu-", SID_REVISION);
  1464. //
  1465. // prepare SidIdentifierAuthority
  1466. if ((psia->Value[0] != 0) || (psia->Value[1] != 0))
  1467. {
  1468. dwSidSize += wsprintfW(wszTextualSid + dwSidSize,
  1469. L"0x%02hx%02hx%02hx%02hx%02hx%02hx",
  1470. (USHORT)psia->Value[0],
  1471. (USHORT)psia->Value[1],
  1472. (USHORT)psia->Value[2],
  1473. (USHORT)psia->Value[3],
  1474. (USHORT)psia->Value[4],
  1475. (USHORT)psia->Value[5]);
  1476. }
  1477. else
  1478. {
  1479. dwSidSize += wsprintfW(wszTextualSid + dwSidSize,
  1480. L"%lu",
  1481. (ULONG)(psia->Value[5])
  1482. + (ULONG)(psia->Value[4] << 8)
  1483. + (ULONG)(psia->Value[3] << 16)
  1484. + (ULONG)(psia->Value[2] << 24));
  1485. }
  1486. //
  1487. // loop through SidSubAuthorities
  1488. for (dwCounter = 0; dwCounter < dwSubAuthorities; dwCounter++)
  1489. {
  1490. dwSidSize += wsprintfW(wszTextualSid + dwSidSize,
  1491. L"-%lu",
  1492. *GetSidSubAuthority(pSid, dwCounter));
  1493. }
  1494. *dwBufferLen = dwSidSize + 1; // tell caller how many chars (include NULL)
  1495. dwReturn = ERROR_SUCCESS;
  1496. ErrorExit:
  1497. return dwReturn;
  1498. }
  1499. /*static*/ DWORD
  1500. GetUserSid(
  1501. PTOKEN_USER *pptgUser,
  1502. DWORD *pcbUser,
  1503. BOOL *pfAlloced)
  1504. {
  1505. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  1506. BOOL fSts;
  1507. DWORD dwSts;
  1508. HANDLE hToken = 0;
  1509. *pfAlloced = FALSE;
  1510. dwSts = OpenCallerToken(TOKEN_QUERY, &hToken);
  1511. if (ERROR_SUCCESS != dwSts)
  1512. {
  1513. dwReturn = dwSts;
  1514. goto ErrorExit;
  1515. }
  1516. fSts = GetTokenInformation(hToken, // identifies access token
  1517. TokenUser, // TokenUser info type
  1518. *pptgUser, // retrieved info buffer
  1519. *pcbUser, // size of buffer passed-in
  1520. pcbUser); // required buffer size
  1521. if (!fSts)
  1522. {
  1523. dwSts = GetLastError();
  1524. if (ERROR_INSUFFICIENT_BUFFER != dwSts)
  1525. {
  1526. dwReturn = dwSts;
  1527. goto ErrorExit;
  1528. }
  1529. //
  1530. // try again with the specified buffer size
  1531. //
  1532. *pptgUser = (PTOKEN_USER)ContInfoAlloc(*pcbUser);
  1533. if (NULL == *pptgUser)
  1534. {
  1535. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  1536. goto ErrorExit;
  1537. }
  1538. *pfAlloced = TRUE;
  1539. fSts = GetTokenInformation(hToken, // identifies access token
  1540. TokenUser, // TokenUser info type
  1541. *pptgUser, // retrieved info buffer
  1542. *pcbUser, // size of buffer passed-in
  1543. pcbUser); // required buffer size
  1544. if (!fSts)
  1545. {
  1546. dwReturn = GetLastError();
  1547. goto ErrorExit;
  1548. }
  1549. }
  1550. dwReturn = ERROR_SUCCESS;
  1551. ErrorExit:
  1552. if (NULL != hToken)
  1553. CloseHandle(hToken);
  1554. return dwReturn;
  1555. }
  1556. DWORD
  1557. GetUserTextualSidA(
  1558. LPSTR lpBuffer,
  1559. LPDWORD nSize)
  1560. {
  1561. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  1562. DWORD dwSts;
  1563. BYTE FastBuffer[FAST_BUF_SIZE];
  1564. PTOKEN_USER ptgUser;
  1565. DWORD cbUser;
  1566. BOOL fAlloced = FALSE;
  1567. ptgUser = (PTOKEN_USER)FastBuffer; // try fast buffer first
  1568. cbUser = FAST_BUF_SIZE;
  1569. dwSts = GetUserSid(&ptgUser, &cbUser, &fAlloced);
  1570. if (ERROR_SUCCESS != dwSts)
  1571. {
  1572. dwReturn = dwSts;
  1573. goto ErrorExit;
  1574. }
  1575. //
  1576. // obtain the textual representaion of the Sid
  1577. //
  1578. dwSts = GetTextualSidA(ptgUser->User.Sid, // user binary Sid
  1579. lpBuffer, // buffer for TextualSid
  1580. nSize);
  1581. if (ERROR_SUCCESS != dwSts)
  1582. {
  1583. dwReturn = dwSts;
  1584. goto ErrorExit;
  1585. }
  1586. dwReturn = ERROR_SUCCESS;
  1587. ErrorExit:
  1588. if (fAlloced)
  1589. {
  1590. if (NULL != ptgUser)
  1591. ContInfoFree(ptgUser);
  1592. }
  1593. return dwReturn;
  1594. }
  1595. DWORD
  1596. GetUserTextualSidW(
  1597. LPWSTR lpBuffer,
  1598. LPDWORD nSize)
  1599. {
  1600. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  1601. DWORD dwSts;
  1602. BYTE FastBuffer[FAST_BUF_SIZE];
  1603. PTOKEN_USER ptgUser;
  1604. DWORD cbUser;
  1605. BOOL fAlloced = FALSE;
  1606. ptgUser = (PTOKEN_USER)FastBuffer; // try fast buffer first
  1607. cbUser = FAST_BUF_SIZE;
  1608. dwSts = GetUserSid(&ptgUser, &cbUser, &fAlloced);
  1609. if (ERROR_SUCCESS != dwSts)
  1610. {
  1611. dwReturn = dwSts;
  1612. goto ErrorExit;
  1613. }
  1614. //
  1615. // obtain the textual representaion of the Sid
  1616. //
  1617. dwSts = GetTextualSidW(ptgUser->User.Sid, // user binary Sid
  1618. lpBuffer, // buffer for TextualSid
  1619. nSize);
  1620. if (ERROR_SUCCESS != dwSts)
  1621. {
  1622. dwReturn = dwSts;
  1623. goto ErrorExit;
  1624. }
  1625. dwReturn = ERROR_SUCCESS;
  1626. ErrorExit:
  1627. if (fAlloced)
  1628. {
  1629. if (NULL != ptgUser)
  1630. ContInfoFree(ptgUser);
  1631. }
  1632. return dwReturn;
  1633. }
  1634. /*static*/ DWORD
  1635. GetUserDirectory(
  1636. IN BOOL fMachineKeyset,
  1637. OUT LPWSTR pwszUser,
  1638. OUT DWORD *pcbUser)
  1639. {
  1640. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  1641. DWORD dwSts;
  1642. if (fMachineKeyset)
  1643. {
  1644. wcscpy(pwszUser, MACHINE_KEYS_DIR);
  1645. *pcbUser = wcslen(pwszUser) + 1;
  1646. }
  1647. else
  1648. {
  1649. if (FIsWinNT())
  1650. {
  1651. dwSts = GetUserTextualSidW(pwszUser, pcbUser);
  1652. if (ERROR_SUCCESS != dwSts)
  1653. {
  1654. dwReturn = dwSts;
  1655. goto ErrorExit;
  1656. }
  1657. }
  1658. else
  1659. {
  1660. dwReturn = (DWORD)NTE_FAIL;
  1661. goto ErrorExit;
  1662. }
  1663. }
  1664. dwReturn = ERROR_SUCCESS;
  1665. ErrorExit:
  1666. return dwReturn;
  1667. }
  1668. #define WSZRSAPRODUCTSTRING L"\\Microsoft\\Crypto\\RSA\\"
  1669. #define WSZDSSPRODUCTSTRING L"\\Microsoft\\Crypto\\DSS\\"
  1670. #define PRODUCTSTRINGLEN sizeof(WSZRSAPRODUCTSTRING) - sizeof(WCHAR)
  1671. typedef HRESULT
  1672. (WINAPI *SHGETFOLDERPATHW)(
  1673. HWND hwnd,
  1674. int csidl,
  1675. HANDLE hToken,
  1676. DWORD dwFlags,
  1677. LPWSTR pwszPath);
  1678. /*static*/ DWORD
  1679. GetUserStorageArea(
  1680. IN DWORD dwProvType,
  1681. IN BOOL fMachineKeyset,
  1682. IN BOOL fOldWin2KMachineKeyPath,
  1683. OUT BOOL *pfIsLocalSystem, // used if fMachineKeyset is FALSE, in this
  1684. // case TRUE is returned if running as Local
  1685. // System
  1686. IN OUT LPWSTR *ppwszUserStorageArea)
  1687. {
  1688. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  1689. WCHAR wszUserStorageRoot[MAX_PATH+1];
  1690. DWORD cbUserStorageRoot;
  1691. WCHAR *wszProductString = NULL;
  1692. WCHAR wszUser[MAX_PATH];
  1693. DWORD cbUser;
  1694. DWORD cchUser = MAX_PATH;
  1695. HANDLE hToken = NULL;
  1696. DWORD dwTempProfileFlags = 0;
  1697. DWORD dwSts;
  1698. BOOL fSts;
  1699. HMODULE hShell32 = NULL;
  1700. PBYTE pbCurrent;
  1701. *pfIsLocalSystem = FALSE;
  1702. if ((PROV_RSA_SIG == dwProvType)
  1703. || (PROV_RSA_FULL == dwProvType)
  1704. || (PROV_RSA_SCHANNEL == dwProvType)
  1705. || (PROV_RSA_AES == dwProvType))
  1706. {
  1707. wszProductString = WSZRSAPRODUCTSTRING;
  1708. }
  1709. else if ((PROV_DSS == dwProvType)
  1710. || (PROV_DSS_DH == dwProvType)
  1711. || (PROV_DH_SCHANNEL == dwProvType))
  1712. {
  1713. wszProductString = WSZDSSPRODUCTSTRING;
  1714. }
  1715. //
  1716. // check if running in the LocalSystem context
  1717. //
  1718. if (!fMachineKeyset)
  1719. {
  1720. dwSts = IsThreadLocalSystem(pfIsLocalSystem);
  1721. if (ERROR_SUCCESS != dwSts)
  1722. {
  1723. dwReturn = dwSts;
  1724. goto ErrorExit;
  1725. }
  1726. }
  1727. //
  1728. // determine path to per-user storage area, based on whether this
  1729. // is a local machine disposition call or a per-user disposition call.
  1730. //
  1731. if (fMachineKeyset || *pfIsLocalSystem)
  1732. {
  1733. if (!fOldWin2KMachineKeyPath)
  1734. {
  1735. // Should not call SHGetFolderPathW with a caller token for
  1736. // the local machine case. The COMMON_APPDATA location is
  1737. // per-machine, not per-user, therefor we shouldn't be supplying
  1738. // a user token. The shell team should make their own change to ignore
  1739. // this, though.
  1740. /*
  1741. dwSts = OpenCallerToken(TOKEN_QUERY | TOKEN_IMPERSONATE,
  1742. &hToken);
  1743. if (ERROR_SUCCESS != dwSts)
  1744. {
  1745. dwReturn = dwSts;
  1746. goto ErrorExit;
  1747. }
  1748. */
  1749. dwSts = (DWORD) SHGetFolderPathW(NULL,
  1750. CSIDL_COMMON_APPDATA | CSIDL_FLAG_CREATE,
  1751. 0 /*hToken*/,
  1752. 0,
  1753. wszUserStorageRoot);
  1754. if (dwSts != ERROR_SUCCESS)
  1755. {
  1756. dwReturn = dwSts;
  1757. goto ErrorExit;
  1758. }
  1759. /*
  1760. CloseHandle(hToken);
  1761. hToken = NULL;
  1762. */
  1763. cbUserStorageRoot = wcslen( wszUserStorageRoot ) * sizeof(WCHAR);
  1764. }
  1765. else
  1766. {
  1767. cbUserStorageRoot = GetSystemDirectoryW(wszUserStorageRoot,
  1768. MAX_PATH);
  1769. cbUserStorageRoot *= sizeof(WCHAR);
  1770. }
  1771. }
  1772. else
  1773. {
  1774. // check if the profile is temporary
  1775. fSts = GetProfileType(&dwTempProfileFlags);
  1776. if (!fSts)
  1777. {
  1778. dwReturn = GetLastError();
  1779. goto ErrorExit;
  1780. }
  1781. if ((dwTempProfileFlags & PT_MANDATORY)
  1782. || ((dwTempProfileFlags & PT_TEMPORARY)
  1783. && !(dwTempProfileFlags & PT_ROAMING)))
  1784. {
  1785. dwReturn = (DWORD)NTE_TEMPORARY_PROFILE;
  1786. goto ErrorExit;
  1787. }
  1788. dwSts = OpenCallerToken(TOKEN_QUERY | TOKEN_IMPERSONATE,
  1789. &hToken);
  1790. if (ERROR_SUCCESS != dwSts)
  1791. {
  1792. dwReturn = dwSts;
  1793. goto ErrorExit;
  1794. }
  1795. // Use new private shell entry point for finding user storage path
  1796. if (ERROR_SUCCESS !=
  1797. (dwSts = GetUserAppDataPathW(hToken, wszUserStorageRoot)))
  1798. {
  1799. dwReturn = dwSts;
  1800. goto ErrorExit;
  1801. }
  1802. CloseHandle(hToken);
  1803. hToken = NULL;
  1804. cbUserStorageRoot = wcslen( wszUserStorageRoot ) * sizeof(WCHAR);
  1805. }
  1806. if (cbUserStorageRoot == 0)
  1807. {
  1808. dwReturn = (DWORD)NTE_FAIL;
  1809. goto ErrorExit;
  1810. }
  1811. //
  1812. // get the user name associated with the call.
  1813. // Note: this is the textual Sid on NT, and will fail on Win95.
  1814. //
  1815. dwSts = GetUserDirectory(fMachineKeyset, wszUser, &cchUser);
  1816. if (ERROR_SUCCESS != dwSts)
  1817. {
  1818. dwReturn = dwSts;
  1819. goto ErrorExit;
  1820. }
  1821. cbUser = (cchUser-1) * sizeof(WCHAR);
  1822. *ppwszUserStorageArea = (LPWSTR)ContInfoAlloc(cbUserStorageRoot
  1823. + PRODUCTSTRINGLEN
  1824. + cbUser
  1825. + 2 * sizeof(WCHAR)); // trailing slash and NULL
  1826. if (NULL == *ppwszUserStorageArea)
  1827. {
  1828. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  1829. goto ErrorExit;
  1830. }
  1831. pbCurrent = (PBYTE)*ppwszUserStorageArea;
  1832. CopyMemory(pbCurrent, wszUserStorageRoot, cbUserStorageRoot);
  1833. pbCurrent += cbUserStorageRoot;
  1834. CopyMemory(pbCurrent, wszProductString, PRODUCTSTRINGLEN);
  1835. pbCurrent += PRODUCTSTRINGLEN;
  1836. CopyMemory(pbCurrent, wszUser, cbUser);
  1837. pbCurrent += cbUser; // note: cbUser does not include terminal NULL
  1838. ((LPSTR)pbCurrent)[0] = '\\';
  1839. ((LPSTR)pbCurrent)[1] = '\0';
  1840. dwSts = CreateNestedDirectories(*ppwszUserStorageArea,
  1841. (LPWSTR)((LPBYTE)*ppwszUserStorageArea
  1842. + cbUserStorageRoot
  1843. + sizeof(WCHAR)),
  1844. fMachineKeyset);
  1845. if (ERROR_SUCCESS != dwSts)
  1846. {
  1847. dwReturn = dwSts;
  1848. goto ErrorExit;
  1849. }
  1850. dwReturn = ERROR_SUCCESS;
  1851. ErrorExit:
  1852. if (NULL != hToken)
  1853. CloseHandle(hToken);
  1854. return dwReturn;
  1855. }
  1856. /*static*/ DWORD
  1857. GetFilePath(
  1858. IN LPCWSTR pwszUserStorageArea,
  1859. IN LPCWSTR pwszFileName,
  1860. IN OUT LPWSTR *ppwszFilePath)
  1861. {
  1862. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  1863. DWORD cbUserStorageArea;
  1864. DWORD cbFileName;
  1865. cbUserStorageArea = wcslen(pwszUserStorageArea) * sizeof(WCHAR);
  1866. cbFileName = wcslen(pwszFileName) * sizeof(WCHAR);
  1867. *ppwszFilePath = (LPWSTR)ContInfoAlloc(cbUserStorageArea
  1868. + cbFileName
  1869. + sizeof(WCHAR));
  1870. if (*ppwszFilePath == NULL)
  1871. {
  1872. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  1873. goto ErrorExit;
  1874. }
  1875. CopyMemory(*ppwszFilePath, pwszUserStorageArea, cbUserStorageArea);
  1876. CopyMemory((LPBYTE)*ppwszFilePath+cbUserStorageArea, pwszFileName, cbFileName + sizeof(WCHAR));
  1877. dwReturn = ERROR_SUCCESS;
  1878. ErrorExit:
  1879. return dwReturn;
  1880. }
  1881. static DWORD
  1882. rgdwCreateFileRetryMilliseconds[] =
  1883. { 1, 10, 100, 500, 1000, 5000 };
  1884. #define MAX_CREATE_FILE_RETRY_COUNT \
  1885. (sizeof(rgdwCreateFileRetryMilliseconds) \
  1886. / sizeof(rgdwCreateFileRetryMilliseconds[0]))
  1887. /*static*/ DWORD
  1888. MyCreateFile(
  1889. IN BOOL fMachineKeyset, // indicates if this is a machine keyset
  1890. IN LPCWSTR wszFilePath, // pointer to name of the file
  1891. IN DWORD dwDesiredAccess, // access (read-write) mode
  1892. IN DWORD dwShareMode, // share mode
  1893. IN DWORD dwCreationDisposition, // how to create
  1894. IN DWORD dwAttribs, // file attributes
  1895. OUT HANDLE *phFile) // Resultant handle
  1896. {
  1897. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  1898. HANDLE hToken = 0;
  1899. BYTE rgbPriv[sizeof(PRIVILEGE_SET) + sizeof(LUID_AND_ATTRIBUTES)];
  1900. PRIVILEGE_SET *pPriv = (PRIVILEGE_SET*)rgbPriv;
  1901. BOOL fPrivSet = FALSE;
  1902. HANDLE hFile = INVALID_HANDLE_VALUE;
  1903. DWORD dwSts, dwSavedSts;
  1904. BOOL fSts;
  1905. hFile = CreateFileW(wszFilePath,
  1906. dwDesiredAccess,
  1907. dwShareMode,
  1908. NULL,
  1909. dwCreationDisposition,
  1910. dwAttribs,
  1911. NULL);
  1912. if (INVALID_HANDLE_VALUE == hFile)
  1913. {
  1914. dwSts = GetLastError();
  1915. // check if machine keyset
  1916. if (fMachineKeyset)
  1917. {
  1918. dwSavedSts = dwSts;
  1919. // open a token handle
  1920. dwSts = OpenCallerToken(TOKEN_QUERY, &hToken);
  1921. if (ERROR_SUCCESS != dwSts)
  1922. {
  1923. dwReturn = dwSts;
  1924. goto ErrorExit;
  1925. }
  1926. memset(rgbPriv, 0, sizeof(rgbPriv));
  1927. pPriv->PrivilegeCount = 1;
  1928. // reading file
  1929. if (dwDesiredAccess & GENERIC_READ)
  1930. {
  1931. fSts = LookupPrivilegeValue(NULL, SE_BACKUP_NAME,
  1932. &(pPriv->Privilege[0].Luid));
  1933. }
  1934. // writing
  1935. else
  1936. {
  1937. fSts = LookupPrivilegeValue(NULL, SE_RESTORE_NAME,
  1938. &(pPriv->Privilege[0].Luid));
  1939. }
  1940. if (!fSts)
  1941. {
  1942. dwReturn = GetLastError();
  1943. goto ErrorExit;
  1944. }
  1945. // check if the BACKUP or RESTORE privileges are set
  1946. pPriv->Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
  1947. fSts = PrivilegeCheck(hToken, pPriv, &fPrivSet);
  1948. if (!fSts)
  1949. {
  1950. dwReturn = GetLastError();
  1951. goto ErrorExit;
  1952. }
  1953. if (fPrivSet)
  1954. {
  1955. hFile = CreateFileW(wszFilePath,
  1956. dwDesiredAccess,
  1957. dwShareMode,
  1958. NULL,
  1959. dwCreationDisposition,
  1960. dwAttribs | FILE_FLAG_BACKUP_SEMANTICS,
  1961. NULL);
  1962. if (INVALID_HANDLE_VALUE == hFile)
  1963. {
  1964. dwReturn = GetLastError();
  1965. goto ErrorExit;
  1966. }
  1967. }
  1968. else
  1969. {
  1970. dwReturn = dwSavedSts;
  1971. goto ErrorExit;
  1972. }
  1973. }
  1974. else
  1975. {
  1976. dwReturn = dwSts;
  1977. goto ErrorExit;
  1978. }
  1979. }
  1980. *phFile = hFile;
  1981. dwReturn = ERROR_SUCCESS;
  1982. ErrorExit:
  1983. if (NULL != hToken)
  1984. CloseHandle(hToken);
  1985. return dwReturn;
  1986. }
  1987. /*static*/ DWORD
  1988. OpenFileInStorageArea(
  1989. IN BOOL fMachineKeyset,
  1990. IN DWORD dwDesiredAccess,
  1991. IN LPCWSTR wszUserStorageArea,
  1992. IN LPCWSTR wszFileName,
  1993. IN OUT HANDLE *phFile)
  1994. {
  1995. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  1996. LPWSTR wszFilePath = NULL;
  1997. DWORD dwShareMode = 0;
  1998. DWORD dwCreationDistribution = OPEN_EXISTING;
  1999. DWORD dwRetryCount;
  2000. DWORD dwAttribs = 0;
  2001. DWORD dwSts;
  2002. *phFile = INVALID_HANDLE_VALUE;
  2003. if (dwDesiredAccess & GENERIC_READ)
  2004. {
  2005. dwShareMode |= FILE_SHARE_READ;
  2006. dwCreationDistribution = OPEN_EXISTING;
  2007. }
  2008. if (dwDesiredAccess & GENERIC_WRITE)
  2009. {
  2010. dwShareMode = 0;
  2011. dwCreationDistribution = OPEN_ALWAYS;
  2012. dwAttribs = FILE_ATTRIBUTE_SYSTEM;
  2013. }
  2014. dwSts = GetFilePath(wszUserStorageArea, wszFileName, &wszFilePath);
  2015. if (ERROR_SUCCESS != dwSts)
  2016. {
  2017. dwReturn = dwSts;
  2018. goto ErrorExit;
  2019. }
  2020. dwRetryCount = 0;
  2021. for (;;)
  2022. {
  2023. dwSts = MyCreateFile(fMachineKeyset,
  2024. wszFilePath,
  2025. dwDesiredAccess,
  2026. dwShareMode,
  2027. dwCreationDistribution,
  2028. dwAttribs | FILE_FLAG_SEQUENTIAL_SCAN,
  2029. phFile);
  2030. if (ERROR_SUCCESS == dwSts)
  2031. break;
  2032. if (((ERROR_SHARING_VIOLATION == dwSts)
  2033. || (ERROR_ACCESS_DENIED == dwSts))
  2034. && (MAX_CREATE_FILE_RETRY_COUNT > dwRetryCount))
  2035. {
  2036. Sleep(rgdwCreateFileRetryMilliseconds[dwRetryCount]);
  2037. dwRetryCount++;
  2038. }
  2039. else
  2040. {
  2041. if (ERROR_FILE_NOT_FOUND == dwSts)
  2042. dwReturn = (DWORD)NTE_BAD_KEYSET;
  2043. else
  2044. dwReturn = dwSts;
  2045. goto ErrorExit;
  2046. }
  2047. }
  2048. dwReturn = ERROR_SUCCESS;
  2049. ErrorExit:
  2050. if (NULL != wszFilePath)
  2051. ContInfoFree(wszFilePath);
  2052. return dwReturn;
  2053. }
  2054. /*static*/ DWORD
  2055. FindClosestFileInStorageArea(
  2056. IN LPCWSTR pwszUserStorageArea,
  2057. IN LPCSTR pszContainer,
  2058. OUT LPWSTR pwszNewFileName,
  2059. IN OUT HANDLE *phFile)
  2060. {
  2061. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  2062. LPWSTR pwszFilePath = NULL;
  2063. WCHAR rgwszNewFileName[35];
  2064. DWORD dwShareMode = 0;
  2065. DWORD dwCreationDistribution = OPEN_EXISTING;
  2066. HANDLE hFind = INVALID_HANDLE_VALUE;
  2067. WIN32_FIND_DATAW FindData;
  2068. DWORD dwSts;
  2069. memset(&FindData, 0, sizeof(FindData));
  2070. memset(rgwszNewFileName, 0, sizeof(rgwszNewFileName));
  2071. *phFile = INVALID_HANDLE_VALUE;
  2072. dwShareMode |= FILE_SHARE_READ;
  2073. dwCreationDistribution = OPEN_EXISTING;
  2074. // get the stringized hash of the container name
  2075. dwSts = GetHashOfContainer(pszContainer, rgwszNewFileName);
  2076. if (ERROR_SUCCESS != dwSts)
  2077. {
  2078. dwReturn = dwSts;
  2079. goto ErrorExit;
  2080. }
  2081. // ContInfoAlloc zeros memory so no need to set NULL terminator
  2082. rgwszNewFileName[32] = '_';
  2083. rgwszNewFileName[33] = '*';
  2084. dwSts = GetFilePath(pwszUserStorageArea, rgwszNewFileName, &pwszFilePath);
  2085. if (ERROR_SUCCESS != dwSts)
  2086. {
  2087. dwReturn = dwSts;
  2088. goto ErrorExit;
  2089. }
  2090. hFind = FindFirstFileExW(pwszFilePath,
  2091. FindExInfoStandard,
  2092. &FindData,
  2093. FindExSearchNameMatch,
  2094. NULL,
  2095. 0);
  2096. if (hFind == INVALID_HANDLE_VALUE)
  2097. {
  2098. dwSts = GetLastError();
  2099. if (ERROR_FILE_NOT_FOUND == dwSts)
  2100. dwReturn = (DWORD)NTE_BAD_KEYSET;
  2101. else
  2102. dwReturn = dwSts;
  2103. goto ErrorExit;
  2104. }
  2105. ContInfoFree(pwszFilePath);
  2106. pwszFilePath = NULL;
  2107. dwSts = GetFilePath(pwszUserStorageArea, FindData.cFileName,
  2108. &pwszFilePath);
  2109. if (ERROR_SUCCESS != dwSts)
  2110. {
  2111. dwReturn = dwSts;
  2112. goto ErrorExit;
  2113. }
  2114. *phFile = CreateFileW(pwszFilePath,
  2115. GENERIC_READ,
  2116. dwShareMode,
  2117. NULL,
  2118. dwCreationDistribution,
  2119. FILE_FLAG_SEQUENTIAL_SCAN,
  2120. NULL);
  2121. if (*phFile == INVALID_HANDLE_VALUE)
  2122. {
  2123. dwSts = GetLastError();
  2124. if (ERROR_FILE_NOT_FOUND == dwSts)
  2125. dwReturn = (DWORD)NTE_BAD_KEYSET;
  2126. else
  2127. dwReturn = dwSts;
  2128. goto ErrorExit;
  2129. }
  2130. // allocate and copy in the real file name to be returned
  2131. wcscpy(pwszNewFileName, FindData.cFileName);
  2132. dwReturn = ERROR_SUCCESS;
  2133. ErrorExit:
  2134. if (NULL != hFind)
  2135. FindClose(hFind);
  2136. if (NULL != pwszFilePath)
  2137. ContInfoFree(pwszFilePath);
  2138. return dwReturn;
  2139. }
  2140. //
  2141. // This function gets the determines if the user associated with the
  2142. // specified token is the Local System account.
  2143. //
  2144. /*static*/ DWORD
  2145. ZeroizeFile(
  2146. IN LPCWSTR wszFilePath)
  2147. {
  2148. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  2149. HANDLE hFile = INVALID_HANDLE_VALUE;
  2150. BYTE *pb = NULL;
  2151. DWORD cb;
  2152. DWORD dwBytesWritten = 0;
  2153. DWORD dwSts;
  2154. BOOL fSts;
  2155. hFile = CreateFileW(wszFilePath,
  2156. GENERIC_WRITE,
  2157. 0,
  2158. NULL,
  2159. OPEN_EXISTING,
  2160. FILE_ATTRIBUTE_SYSTEM,
  2161. NULL);
  2162. if (INVALID_HANDLE_VALUE == hFile)
  2163. {
  2164. dwSts = GetLastError();
  2165. if (ERROR_FILE_NOT_FOUND == dwSts)
  2166. dwReturn = (DWORD)NTE_BAD_KEYSET;
  2167. else
  2168. dwReturn = dwSts;
  2169. goto ErrorExit;
  2170. }
  2171. cb = GetFileSize(hFile, NULL);
  2172. if ((DWORD)(-1) == cb)
  2173. {
  2174. dwReturn = GetLastError();
  2175. goto ErrorExit;
  2176. }
  2177. pb = ContInfoAlloc(cb);
  2178. if (NULL == pb)
  2179. {
  2180. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  2181. goto ErrorExit;
  2182. }
  2183. fSts = WriteFile(hFile, pb, cb, &dwBytesWritten, NULL);
  2184. if (!fSts)
  2185. {
  2186. dwReturn = GetLastError();
  2187. goto ErrorExit;
  2188. }
  2189. dwReturn = ERROR_SUCCESS;
  2190. ErrorExit:
  2191. if (NULL != pb)
  2192. ContInfoFree(pb);
  2193. if (INVALID_HANDLE_VALUE != hFile)
  2194. CloseHandle(hFile);
  2195. return dwReturn;
  2196. }
  2197. /*static*/ DWORD
  2198. DeleteFileInStorageArea(
  2199. IN LPCWSTR wszUserStorageArea,
  2200. IN LPCWSTR wszFileName)
  2201. {
  2202. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  2203. LPWSTR wszFilePath = NULL;
  2204. DWORD cbUserStorageArea;
  2205. DWORD cbFileName;
  2206. DWORD dwSts;
  2207. cbUserStorageArea = wcslen(wszUserStorageArea) * sizeof(WCHAR);
  2208. cbFileName = wcslen(wszFileName) * sizeof(WCHAR);
  2209. wszFilePath = (LPWSTR)ContInfoAlloc((cbUserStorageArea + cbFileName + 1) * sizeof(WCHAR));
  2210. if (wszFilePath == NULL)
  2211. {
  2212. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  2213. goto ErrorExit;
  2214. }
  2215. CopyMemory(wszFilePath, wszUserStorageArea, cbUserStorageArea);
  2216. CopyMemory((LPBYTE)wszFilePath + cbUserStorageArea, wszFileName,
  2217. cbFileName + sizeof(WCHAR));
  2218. // write a file of the same size with all zeros first
  2219. dwSts = ZeroizeFile(wszFilePath);
  2220. if (ERROR_SUCCESS != dwSts)
  2221. {
  2222. dwReturn = dwSts;
  2223. goto ErrorExit;
  2224. }
  2225. if (!DeleteFileW(wszFilePath))
  2226. {
  2227. dwReturn = GetLastError();
  2228. goto ErrorExit;
  2229. }
  2230. dwReturn = ERROR_SUCCESS;
  2231. ErrorExit:
  2232. if (NULL != wszFilePath)
  2233. ContInfoFree(wszFilePath);
  2234. return dwReturn;
  2235. }
  2236. DWORD
  2237. SetContainerUserName(
  2238. IN LPSTR pszUserName,
  2239. IN PKEY_CONTAINER_INFO pContInfo)
  2240. {
  2241. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  2242. pContInfo->pszUserName = (LPSTR)ContInfoAlloc((strlen(pszUserName) + 1) * sizeof(CHAR));
  2243. if (NULL == pContInfo->pszUserName)
  2244. {
  2245. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  2246. goto ErrorExit;
  2247. }
  2248. strcpy(pContInfo->pszUserName, pszUserName);
  2249. dwReturn = ERROR_SUCCESS;
  2250. ErrorExit:
  2251. return dwReturn;
  2252. }
  2253. DWORD
  2254. ReadContainerInfo(
  2255. IN DWORD dwProvType,
  2256. IN LPSTR pszContainerName,
  2257. IN BOOL fMachineKeyset,
  2258. IN DWORD dwFlags,
  2259. OUT PKEY_CONTAINER_INFO pContInfo)
  2260. {
  2261. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  2262. HANDLE hMap = NULL;
  2263. BYTE *pbFile = NULL;
  2264. DWORD cbFile;
  2265. DWORD cb;
  2266. HANDLE hFile = INVALID_HANDLE_VALUE;
  2267. KEY_EXPORTABILITY_LENS Exportability;
  2268. LPWSTR pwszFileName = NULL;
  2269. LPWSTR pwszFilePath = NULL;
  2270. WCHAR rgwszOtherMachineFileName[84];
  2271. BOOL fGetUserNameFromFile = FALSE;
  2272. BOOL fIsLocalSystem = FALSE;
  2273. BOOL fRetryWithHashedName = TRUE;
  2274. DWORD cch = 0;
  2275. DWORD dwSts;
  2276. memset(&Exportability, 0, sizeof(Exportability));
  2277. // get the correct storage area (directory)
  2278. dwSts = GetUserStorageArea(dwProvType, fMachineKeyset, FALSE,
  2279. &fIsLocalSystem, &pwszFilePath);
  2280. if (ERROR_SUCCESS != dwSts)
  2281. {
  2282. dwReturn = dwSts;
  2283. goto ErrorExit;
  2284. }
  2285. // check if the length of the container name is the length of a new unique container,
  2286. // then try with the container name which was passed in, if this fails
  2287. // then try with the container name with the machine GUID appended
  2288. if (69 == strlen(pszContainerName))
  2289. {
  2290. // convert to UNICODE pszContainerName -> pwszFileName
  2291. cch = MultiByteToWideChar(CP_ACP, MB_COMPOSITE,
  2292. pszContainerName,
  2293. -1, NULL, cch);
  2294. if (0 == cch)
  2295. {
  2296. dwReturn = GetLastError();
  2297. goto ErrorExit;
  2298. }
  2299. pwszFileName = ContInfoAlloc((cch + 1) * sizeof(WCHAR));
  2300. if (NULL == pwszFileName)
  2301. {
  2302. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  2303. goto ErrorExit;
  2304. }
  2305. cch = MultiByteToWideChar(CP_ACP, MB_COMPOSITE,
  2306. pszContainerName,
  2307. -1, pwszFileName, cch);
  2308. if (0 == cch)
  2309. {
  2310. dwReturn = GetLastError();
  2311. goto ErrorExit;
  2312. }
  2313. dwSts = OpenFileInStorageArea(fMachineKeyset, GENERIC_READ,
  2314. pwszFilePath, pwszFileName, &hFile);
  2315. if (ERROR_SUCCESS == dwSts)
  2316. {
  2317. wcscpy(pContInfo->rgwszFileName, pwszFileName);
  2318. // set the flag so the name of the key container will be retrieved
  2319. // from the file
  2320. fGetUserNameFromFile = TRUE;
  2321. fRetryWithHashedName = FALSE;
  2322. }
  2323. }
  2324. if (fRetryWithHashedName)
  2325. {
  2326. dwSts = AddMachineGuidToContainerName(pszContainerName,
  2327. pContInfo->rgwszFileName);
  2328. if (ERROR_SUCCESS != dwSts)
  2329. {
  2330. dwReturn = dwSts;
  2331. goto ErrorExit;
  2332. }
  2333. dwSts = OpenFileInStorageArea(fMachineKeyset, GENERIC_READ,
  2334. pwszFilePath,
  2335. pContInfo->rgwszFileName,
  2336. &hFile);
  2337. if (ERROR_SUCCESS != dwSts)
  2338. {
  2339. if ((ERROR_ACCESS_DENIED == dwSts) && (dwFlags & CRYPT_NEWKEYSET))
  2340. {
  2341. dwReturn = (DWORD)NTE_EXISTS;
  2342. goto ErrorExit;
  2343. }
  2344. if (NTE_BAD_KEYSET == dwSts)
  2345. {
  2346. if (fMachineKeyset || fIsLocalSystem)
  2347. {
  2348. dwReturn = dwSts;
  2349. goto ErrorExit;
  2350. }
  2351. else
  2352. {
  2353. memset(rgwszOtherMachineFileName, 0,
  2354. sizeof(rgwszOtherMachineFileName));
  2355. // try to open any file from another machine with this
  2356. // container name
  2357. dwSts = FindClosestFileInStorageArea(pwszFilePath,
  2358. pszContainerName,
  2359. rgwszOtherMachineFileName,
  2360. &hFile);
  2361. if (ERROR_SUCCESS != dwSts)
  2362. {
  2363. dwReturn = dwSts;
  2364. goto ErrorExit;
  2365. }
  2366. wcscpy(pContInfo->rgwszFileName,
  2367. rgwszOtherMachineFileName);
  2368. }
  2369. }
  2370. }
  2371. }
  2372. if (dwFlags & CRYPT_NEWKEYSET)
  2373. {
  2374. dwReturn = (DWORD)NTE_EXISTS;
  2375. goto ErrorExit;
  2376. }
  2377. cbFile = GetFileSize(hFile, NULL);
  2378. if ((DWORD)(-1) == cbFile)
  2379. {
  2380. dwReturn = GetLastError();
  2381. goto ErrorExit;
  2382. }
  2383. if (sizeof(KEY_CONTAINER_LENS) > cbFile)
  2384. {
  2385. dwSts = (DWORD)NTE_KEYSET_ENTRY_BAD;
  2386. goto ErrorExit;
  2387. }
  2388. hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  2389. if (NULL == hMap)
  2390. {
  2391. dwReturn = GetLastError();
  2392. goto ErrorExit;
  2393. }
  2394. pbFile = (BYTE*)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
  2395. if (NULL == pbFile)
  2396. {
  2397. dwReturn = GetLastError();
  2398. goto ErrorExit;
  2399. }
  2400. // get the length information out of the file
  2401. memcpy(&pContInfo->dwVersion, pbFile, sizeof(DWORD));
  2402. cb = sizeof(DWORD);
  2403. if (KEY_CONTAINER_FILE_FORMAT_VER != pContInfo->dwVersion)
  2404. {
  2405. dwSts = (DWORD)NTE_KEYSET_ENTRY_BAD;
  2406. goto ErrorExit;
  2407. }
  2408. memcpy(&pContInfo->ContLens, pbFile + cb, sizeof(KEY_CONTAINER_LENS));
  2409. cb += sizeof(KEY_CONTAINER_LENS);
  2410. if (pContInfo->fCryptSilent && (0 != pContInfo->ContLens.dwUIOnKey))
  2411. {
  2412. dwReturn = (DWORD)NTE_SILENT_CONTEXT;
  2413. goto ErrorExit;
  2414. }
  2415. // get the private key exportability stuff
  2416. memcpy(&Exportability, pbFile + cb, sizeof(KEY_EXPORTABILITY_LENS));
  2417. cb += sizeof(KEY_EXPORTABILITY_LENS);
  2418. // get the user name
  2419. pContInfo->pszUserName = ContInfoAlloc(pContInfo->ContLens.cbName);
  2420. if (NULL == pContInfo->pszUserName)
  2421. {
  2422. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  2423. goto ErrorExit;
  2424. }
  2425. memcpy(pContInfo->pszUserName, pbFile + cb, pContInfo->ContLens.cbName);
  2426. cb += pContInfo->ContLens.cbName;
  2427. // get the random seed
  2428. pContInfo->pbRandom = ContInfoAlloc(pContInfo->ContLens.cbRandom);
  2429. if (NULL == pContInfo->pbRandom)
  2430. {
  2431. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  2432. goto ErrorExit;
  2433. }
  2434. memcpy(pContInfo->pbRandom, pbFile + cb, pContInfo->ContLens.cbRandom);
  2435. cb += pContInfo->ContLens.cbRandom;
  2436. // get the signature key info out of the file
  2437. if (pContInfo->ContLens.cbSigPub && pContInfo->ContLens.cbSigEncPriv)
  2438. {
  2439. pContInfo->pbSigPub = ContInfoAlloc(pContInfo->ContLens.cbSigPub);
  2440. if (NULL == pContInfo->pbSigPub)
  2441. {
  2442. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  2443. goto ErrorExit;
  2444. }
  2445. memcpy(pContInfo->pbSigPub, pbFile + cb, pContInfo->ContLens.cbSigPub);
  2446. cb += pContInfo->ContLens.cbSigPub;
  2447. pContInfo->pbSigEncPriv = ContInfoAlloc(pContInfo->ContLens.cbSigEncPriv);
  2448. if (NULL == pContInfo->pbSigEncPriv)
  2449. {
  2450. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  2451. goto ErrorExit;
  2452. }
  2453. memcpy(pContInfo->pbSigEncPriv, pbFile + cb,
  2454. pContInfo->ContLens.cbSigEncPriv);
  2455. cb += pContInfo->ContLens.cbSigEncPriv;
  2456. // get the exportability info for the sig key
  2457. dwSts = UnprotectExportabilityFlag(fMachineKeyset, pbFile + cb,
  2458. Exportability.cbSigExportability,
  2459. &pContInfo->fSigExportable);
  2460. if (ERROR_SUCCESS != dwSts)
  2461. {
  2462. dwReturn = dwSts;
  2463. goto ErrorExit;
  2464. }
  2465. cb += Exportability.cbSigExportability;
  2466. }
  2467. // get the signature key info out of the file
  2468. if (pContInfo->ContLens.cbExchPub && pContInfo->ContLens.cbExchEncPriv)
  2469. {
  2470. pContInfo->pbExchPub = ContInfoAlloc(pContInfo->ContLens.cbExchPub);
  2471. if (NULL == pContInfo->pbExchPub)
  2472. {
  2473. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  2474. goto ErrorExit;
  2475. }
  2476. memcpy(pContInfo->pbExchPub, pbFile + cb,
  2477. pContInfo->ContLens.cbExchPub);
  2478. cb += pContInfo->ContLens.cbExchPub;
  2479. pContInfo->pbExchEncPriv = ContInfoAlloc(pContInfo->ContLens.cbExchEncPriv);
  2480. if (NULL == pContInfo->pbExchEncPriv)
  2481. {
  2482. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  2483. goto ErrorExit;
  2484. }
  2485. memcpy(pContInfo->pbExchEncPriv, pbFile + cb,
  2486. pContInfo->ContLens.cbExchEncPriv);
  2487. cb += pContInfo->ContLens.cbExchEncPriv;
  2488. // get the exportability info for the sig key
  2489. dwSts = UnprotectExportabilityFlag(fMachineKeyset, pbFile + cb,
  2490. Exportability.cbExchExportability,
  2491. &pContInfo->fExchExportable);
  2492. if (ERROR_SUCCESS != dwSts)
  2493. {
  2494. dwReturn = dwSts;
  2495. goto ErrorExit;
  2496. }
  2497. cb += Exportability.cbExchExportability;
  2498. }
  2499. pContInfo = NULL;
  2500. dwReturn = ERROR_SUCCESS;
  2501. ErrorExit:
  2502. if (NULL != pwszFileName)
  2503. ContInfoFree(pwszFileName);
  2504. if (NULL != pContInfo)
  2505. FreeContainerInfo(pContInfo);
  2506. if (NULL != pwszFilePath)
  2507. ContInfoFree(pwszFilePath);
  2508. if (NULL != pbFile)
  2509. UnmapViewOfFile(pbFile);
  2510. if (NULL != hMap)
  2511. CloseHandle(hMap);
  2512. if (INVALID_HANDLE_VALUE != hFile)
  2513. CloseHandle(hFile);
  2514. return dwReturn;
  2515. }
  2516. DWORD
  2517. WriteContainerInfo(
  2518. IN DWORD dwProvType,
  2519. IN LPWSTR pwszFileName,
  2520. IN BOOL fMachineKeyset,
  2521. IN PKEY_CONTAINER_INFO pContInfo)
  2522. {
  2523. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  2524. BYTE *pbProtectedSigExportFlag = NULL;
  2525. BYTE *pbProtectedExchExportFlag = NULL;
  2526. KEY_EXPORTABILITY_LENS ExportabilityLens;
  2527. BYTE *pb = NULL;
  2528. DWORD cb;
  2529. LPWSTR pwszFilePath = NULL;
  2530. HANDLE hFile = 0;
  2531. DWORD dwBytesWritten;
  2532. BOOL fIsLocalSystem = FALSE;
  2533. DWORD dwSts;
  2534. BOOL fSts;
  2535. memset(&ExportabilityLens, 0, sizeof(ExportabilityLens));
  2536. // protect the signature exportability flag if necessary
  2537. if (pContInfo->ContLens.cbSigPub && pContInfo->ContLens.cbSigEncPriv)
  2538. {
  2539. dwSts = ProtectExportabilityFlag(pContInfo->fSigExportable,
  2540. fMachineKeyset, &pbProtectedSigExportFlag,
  2541. &ExportabilityLens.cbSigExportability);
  2542. if (ERROR_SUCCESS != dwSts)
  2543. {
  2544. dwReturn = dwSts;
  2545. goto ErrorExit;
  2546. }
  2547. }
  2548. // protect the key exchange exportability flag if necessary
  2549. if (pContInfo->ContLens.cbExchPub && pContInfo->ContLens.cbExchEncPriv)
  2550. {
  2551. dwSts = ProtectExportabilityFlag(pContInfo->fExchExportable,
  2552. fMachineKeyset, &pbProtectedExchExportFlag,
  2553. &ExportabilityLens.cbExchExportability);
  2554. if (ERROR_SUCCESS != dwSts)
  2555. {
  2556. dwReturn = dwSts;
  2557. goto ErrorExit;
  2558. }
  2559. }
  2560. pContInfo->ContLens.cbName = strlen(pContInfo->pszUserName) + sizeof(CHAR);
  2561. // calculate the buffer length required for the container info
  2562. cb = pContInfo->ContLens.cbSigPub + pContInfo->ContLens.cbSigEncPriv +
  2563. pContInfo->ContLens.cbExchPub + pContInfo->ContLens.cbExchEncPriv +
  2564. ExportabilityLens.cbSigExportability +
  2565. ExportabilityLens.cbExchExportability +
  2566. pContInfo->ContLens.cbName +
  2567. pContInfo->ContLens.cbRandom +
  2568. sizeof(KEY_EXPORTABILITY_LENS) + sizeof(KEY_CONTAINER_INFO) +
  2569. sizeof(DWORD);
  2570. pb = (BYTE*)ContInfoAlloc(cb);
  2571. if (NULL == pb)
  2572. {
  2573. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  2574. goto ErrorExit;
  2575. }
  2576. // copy the length information
  2577. pContInfo->dwVersion = KEY_CONTAINER_FILE_FORMAT_VER;
  2578. memcpy(pb, &pContInfo->dwVersion, sizeof(DWORD));
  2579. cb = sizeof(DWORD);
  2580. memcpy(pb + cb, &pContInfo->ContLens, sizeof(KEY_CONTAINER_LENS));
  2581. cb += sizeof(KEY_CONTAINER_LENS);
  2582. if (KEY_CONTAINER_FILE_FORMAT_VER != pContInfo->dwVersion)
  2583. {
  2584. dwReturn = (DWORD)NTE_KEYSET_ENTRY_BAD;
  2585. goto ErrorExit;
  2586. }
  2587. memcpy(pb + cb, &ExportabilityLens, sizeof(KEY_EXPORTABILITY_LENS));
  2588. cb += sizeof(KEY_EXPORTABILITY_LENS);
  2589. // copy the name of the container to the file
  2590. memcpy(pb + cb, pContInfo->pszUserName, pContInfo->ContLens.cbName);
  2591. cb += pContInfo->ContLens.cbName;
  2592. // copy the random seed to the file
  2593. memcpy(pb + cb, pContInfo->pbRandom, pContInfo->ContLens.cbRandom);
  2594. cb += pContInfo->ContLens.cbRandom;
  2595. // copy the signature key info to the file
  2596. if (pContInfo->ContLens.cbSigPub || pContInfo->ContLens.cbSigEncPriv)
  2597. {
  2598. memcpy(pb + cb, pContInfo->pbSigPub, pContInfo->ContLens.cbSigPub);
  2599. cb += pContInfo->ContLens.cbSigPub;
  2600. memcpy(pb + cb, pContInfo->pbSigEncPriv,
  2601. pContInfo->ContLens.cbSigEncPriv);
  2602. cb += pContInfo->ContLens.cbSigEncPriv;
  2603. // write the exportability info for the sig key
  2604. memcpy(pb + cb, pbProtectedSigExportFlag,
  2605. ExportabilityLens.cbSigExportability);
  2606. cb += ExportabilityLens.cbSigExportability;
  2607. }
  2608. // get the signature key info out of the file
  2609. if (pContInfo->ContLens.cbExchPub || pContInfo->ContLens.cbExchEncPriv)
  2610. {
  2611. memcpy(pb + cb, pContInfo->pbExchPub, pContInfo->ContLens.cbExchPub);
  2612. cb += pContInfo->ContLens.cbExchPub;
  2613. memcpy(pb + cb, pContInfo->pbExchEncPriv,
  2614. pContInfo->ContLens.cbExchEncPriv);
  2615. cb += pContInfo->ContLens.cbExchEncPriv;
  2616. // write the exportability info for the sig key
  2617. memcpy(pb + cb, pbProtectedExchExportFlag,
  2618. ExportabilityLens.cbExchExportability);
  2619. cb += ExportabilityLens.cbExchExportability;
  2620. }
  2621. // get the correct storage area (directory)
  2622. dwSts = GetUserStorageArea(dwProvType, fMachineKeyset, FALSE,
  2623. &fIsLocalSystem, &pwszFilePath);
  2624. if (ERROR_SUCCESS != dwSts)
  2625. {
  2626. dwReturn = dwSts;
  2627. goto ErrorExit;
  2628. }
  2629. // open the file to write the information to
  2630. dwSts = OpenFileInStorageArea(fMachineKeyset, GENERIC_WRITE,
  2631. pwszFilePath, pwszFileName,
  2632. &hFile);
  2633. if (ERROR_SUCCESS != dwSts)
  2634. {
  2635. dwReturn = dwSts; // NTE_FAIL
  2636. goto ErrorExit;
  2637. }
  2638. fSts = WriteFile(hFile, pb, cb, &dwBytesWritten, NULL);
  2639. if (!fSts)
  2640. {
  2641. dwReturn = GetLastError(); // NTE_FAIL
  2642. goto ErrorExit;
  2643. }
  2644. dwReturn = ERROR_SUCCESS;
  2645. ErrorExit:
  2646. if (NULL != pwszFilePath)
  2647. ContInfoFree(pwszFilePath);
  2648. if (NULL != pbProtectedSigExportFlag)
  2649. ContInfoFree(pbProtectedSigExportFlag);
  2650. if (NULL != pbProtectedExchExportFlag)
  2651. ContInfoFree(pbProtectedExchExportFlag);
  2652. if (NULL != pb)
  2653. ContInfoFree(pb);
  2654. if (NULL != hFile)
  2655. CloseHandle(hFile);
  2656. return dwReturn;
  2657. }
  2658. /*static*/ DWORD
  2659. DeleteKeyContainer(
  2660. IN LPWSTR pwszFilePath,
  2661. IN LPSTR pszContainer)
  2662. {
  2663. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  2664. LPWSTR pwszFileName = NULL;
  2665. WCHAR rgwchNewFileName[80];
  2666. BOOL fRetryWithHashedName = TRUE;
  2667. DWORD cch = 0;
  2668. DWORD dwSts;
  2669. memset(rgwchNewFileName, 0, sizeof(rgwchNewFileName));
  2670. // first try with the container name which was passed in, if this fails
  2671. if (69 == strlen(pszContainer))
  2672. {
  2673. // convert to UNICODE pszContainer -> pwszFileName
  2674. cch = MultiByteToWideChar(CP_ACP, MB_COMPOSITE,
  2675. pszContainer,
  2676. -1, NULL, cch);
  2677. if (0 == cch)
  2678. {
  2679. dwReturn = GetLastError();
  2680. goto ErrorExit;
  2681. }
  2682. pwszFileName = ContInfoAlloc((cch + 1) * sizeof(WCHAR));
  2683. if (NULL == pwszFileName)
  2684. {
  2685. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  2686. goto ErrorExit;
  2687. }
  2688. cch = MultiByteToWideChar(CP_ACP, MB_COMPOSITE,
  2689. pszContainer,
  2690. -1, pwszFileName, cch);
  2691. if (0 == cch)
  2692. {
  2693. dwReturn = GetLastError();
  2694. goto ErrorExit;
  2695. }
  2696. dwSts = DeleteFileInStorageArea(pwszFilePath, pwszFileName);
  2697. if (ERROR_SUCCESS == dwSts)
  2698. fRetryWithHashedName = FALSE;
  2699. }
  2700. // then try with hash of container name and the machine GUID appended
  2701. if (fRetryWithHashedName)
  2702. {
  2703. dwSts = AddMachineGuidToContainerName(pszContainer,
  2704. rgwchNewFileName);
  2705. if (ERROR_SUCCESS != dwSts)
  2706. {
  2707. dwReturn = dwSts;
  2708. goto ErrorExit;
  2709. }
  2710. dwSts = DeleteFileInStorageArea(pwszFilePath, rgwchNewFileName);
  2711. if (ERROR_SUCCESS != dwSts)
  2712. {
  2713. dwReturn = dwSts;
  2714. goto ErrorExit;
  2715. }
  2716. }
  2717. dwReturn = ERROR_SUCCESS;
  2718. ErrorExit:
  2719. if (NULL != pwszFileName)
  2720. ContInfoFree(pwszFileName);
  2721. return dwReturn;
  2722. }
  2723. DWORD
  2724. DeleteContainerInfo(
  2725. IN DWORD dwProvType,
  2726. IN LPSTR pszContainer,
  2727. IN BOOL fMachineKeyset)
  2728. {
  2729. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  2730. LPWSTR pwszFilePath = NULL;
  2731. HANDLE hFile = INVALID_HANDLE_VALUE;
  2732. BOOL fIsLocalSystem = FALSE;
  2733. WCHAR rgwchNewFileName[80];
  2734. BOOL fDeleted = FALSE;
  2735. DWORD dwSts;
  2736. // get the correct storage area (directory)
  2737. dwSts = GetUserStorageArea(dwProvType, fMachineKeyset, FALSE,
  2738. &fIsLocalSystem, &pwszFilePath);
  2739. if (ERROR_SUCCESS != dwSts)
  2740. {
  2741. dwReturn = dwSts;
  2742. goto ErrorExit;
  2743. }
  2744. dwSts = DeleteKeyContainer(pwszFilePath, pszContainer);
  2745. if (ERROR_SUCCESS != dwSts)
  2746. {
  2747. // for migration of machine keys from system to All Users\App Data
  2748. if (fMachineKeyset)
  2749. {
  2750. ContInfoFree(pwszFilePath);
  2751. pwszFilePath = NULL;
  2752. dwSts = GetUserStorageArea(dwProvType, fMachineKeyset, TRUE,
  2753. &fIsLocalSystem, &pwszFilePath);
  2754. if (ERROR_SUCCESS != dwSts)
  2755. {
  2756. dwReturn = dwSts;
  2757. goto ErrorExit;
  2758. }
  2759. dwSts = DeleteKeyContainer(pwszFilePath, pszContainer);
  2760. if (ERROR_SUCCESS != dwSts)
  2761. {
  2762. dwReturn = dwSts;
  2763. goto ErrorExit;
  2764. }
  2765. else
  2766. {
  2767. fDeleted = TRUE;
  2768. }
  2769. }
  2770. }
  2771. else
  2772. {
  2773. fDeleted = TRUE;
  2774. }
  2775. // there may be other keys created with the same container name on
  2776. // different machines and these also need to be deleted
  2777. for (;;)
  2778. {
  2779. memset(rgwchNewFileName, 0, sizeof(rgwchNewFileName));
  2780. dwSts = FindClosestFileInStorageArea(pwszFilePath, pszContainer,
  2781. rgwchNewFileName, &hFile);
  2782. if (ERROR_SUCCESS != dwSts)
  2783. break;
  2784. CloseHandle(hFile);
  2785. hFile = INVALID_HANDLE_VALUE;
  2786. dwSts = DeleteFileInStorageArea(pwszFilePath, rgwchNewFileName);
  2787. if (ERROR_SUCCESS != dwSts)
  2788. {
  2789. dwReturn = dwSts;
  2790. goto ErrorExit;
  2791. }
  2792. else
  2793. fDeleted = TRUE;
  2794. }
  2795. if (!fDeleted)
  2796. {
  2797. dwReturn = (DWORD)NTE_BAD_KEYSET;
  2798. goto ErrorExit;
  2799. }
  2800. dwReturn = ERROR_SUCCESS;
  2801. ErrorExit:
  2802. if (INVALID_HANDLE_VALUE != hFile)
  2803. CloseHandle(hFile);
  2804. if (NULL != pwszFilePath)
  2805. ContInfoFree(pwszFilePath);
  2806. return dwReturn;
  2807. }
  2808. /*static*/ DWORD
  2809. ReadContainerNameFromFile(
  2810. IN BOOL fMachineKeyset,
  2811. IN LPWSTR pwszFileName,
  2812. IN LPWSTR pwszFilePath,
  2813. OUT LPSTR pszNextContainer,
  2814. IN OUT DWORD *pcbNextContainer)
  2815. {
  2816. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  2817. HANDLE hMap = NULL;
  2818. BYTE *pbFile = NULL;
  2819. HANDLE hFile = INVALID_HANDLE_VALUE;
  2820. DWORD cbFile = 0;
  2821. DWORD *pdwVersion;
  2822. PKEY_CONTAINER_LENS pContLens;
  2823. DWORD dwSts;
  2824. // open the file
  2825. dwSts = OpenFileInStorageArea(fMachineKeyset,
  2826. GENERIC_READ,
  2827. pwszFilePath,
  2828. pwszFileName,
  2829. &hFile);
  2830. if (ERROR_SUCCESS != dwSts)
  2831. {
  2832. if (ERROR_FILE_NOT_FOUND == dwSts)
  2833. dwReturn = (DWORD)NTE_BAD_KEYSET;
  2834. else
  2835. dwReturn = dwSts;
  2836. goto ErrorExit;
  2837. }
  2838. cbFile = GetFileSize(hFile, NULL);
  2839. if ((DWORD)(-1) == cbFile)
  2840. {
  2841. dwReturn = GetLastError();
  2842. goto ErrorExit;
  2843. }
  2844. if ((sizeof(DWORD) + sizeof(KEY_CONTAINER_LENS)) > cbFile)
  2845. {
  2846. dwReturn = (DWORD)NTE_KEYSET_ENTRY_BAD;
  2847. goto ErrorExit;
  2848. }
  2849. hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY,
  2850. 0, 0, NULL);
  2851. if (NULL == hMap)
  2852. {
  2853. dwReturn = GetLastError();
  2854. goto ErrorExit;
  2855. }
  2856. pbFile = (BYTE*)MapViewOfFile(hMap, FILE_MAP_READ,
  2857. 0, 0, 0 );
  2858. if (NULL == pbFile)
  2859. {
  2860. dwReturn = GetLastError();
  2861. goto ErrorExit;
  2862. }
  2863. // get the length information out of the file
  2864. pdwVersion = (DWORD*)pbFile;
  2865. if (KEY_CONTAINER_FILE_FORMAT_VER != *pdwVersion)
  2866. {
  2867. dwReturn = (DWORD)NTE_KEYSET_ENTRY_BAD;
  2868. goto ErrorExit;
  2869. }
  2870. pContLens = (PKEY_CONTAINER_LENS)(pbFile + sizeof(DWORD));
  2871. if (NULL == pszNextContainer)
  2872. {
  2873. *pcbNextContainer = MAX_PATH + 1;
  2874. dwReturn = ERROR_SUCCESS; // Just tell them the length.
  2875. goto ErrorExit;
  2876. }
  2877. if (*pcbNextContainer < pContLens->cbName)
  2878. {
  2879. *pcbNextContainer = MAX_PATH + 1;
  2880. }
  2881. else if ((sizeof(DWORD) + sizeof(KEY_CONTAINER_LENS) +
  2882. sizeof(KEY_EXPORTABILITY_LENS) + pContLens->cbName) > cbFile)
  2883. {
  2884. dwReturn = (DWORD)NTE_KEYSET_ENTRY_BAD;
  2885. goto ErrorExit;
  2886. }
  2887. else
  2888. {
  2889. // get the container name
  2890. memcpy(pszNextContainer,
  2891. pbFile + sizeof(DWORD) + sizeof(KEY_CONTAINER_LENS) +
  2892. sizeof(KEY_EXPORTABILITY_LENS), pContLens->cbName);
  2893. // *pcbNextContainer = pContLens->cbName;
  2894. }
  2895. dwReturn = ERROR_SUCCESS;
  2896. ErrorExit:
  2897. if (NULL != pbFile)
  2898. UnmapViewOfFile(pbFile);
  2899. if (NULL != hMap)
  2900. CloseHandle(hMap);
  2901. if (INVALID_HANDLE_VALUE != hFile)
  2902. CloseHandle(hFile);
  2903. return dwReturn;
  2904. }
  2905. DWORD
  2906. GetUniqueContainerName(
  2907. IN KEY_CONTAINER_INFO *pContInfo,
  2908. OUT BYTE *pbData,
  2909. OUT DWORD *pcbData)
  2910. {
  2911. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  2912. LPSTR pszUniqueContainer = NULL;
  2913. DWORD cch;
  2914. cch = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
  2915. pContInfo->rgwszFileName, -1,
  2916. NULL, 0, NULL, NULL);
  2917. if (0 == cch)
  2918. {
  2919. dwReturn = GetLastError();
  2920. goto ErrorExit;
  2921. }
  2922. pszUniqueContainer = (LPSTR)ContInfoAlloc((cch + 1) * sizeof(WCHAR));
  2923. if (NULL == pszUniqueContainer)
  2924. {
  2925. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  2926. goto ErrorExit;
  2927. }
  2928. cch = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
  2929. pContInfo->rgwszFileName, -1,
  2930. pszUniqueContainer, cch,
  2931. NULL, NULL);
  2932. if (0 == cch)
  2933. {
  2934. dwReturn = GetLastError();
  2935. goto ErrorExit;
  2936. }
  2937. if (pbData == NULL)
  2938. {
  2939. *pcbData = strlen(pszUniqueContainer) + 1;
  2940. }
  2941. else if (*pcbData < (strlen(pszUniqueContainer) + 1))
  2942. {
  2943. *pcbData = strlen(pszUniqueContainer) + 1;
  2944. dwReturn = ERROR_MORE_DATA;
  2945. goto ErrorExit;
  2946. }
  2947. else
  2948. {
  2949. *pcbData = strlen(pszUniqueContainer) + 1;
  2950. strcpy((LPSTR)pbData, pszUniqueContainer);
  2951. }
  2952. dwReturn = ERROR_SUCCESS;
  2953. ErrorExit:
  2954. if (NULL != pszUniqueContainer)
  2955. ContInfoFree(pszUniqueContainer);
  2956. return dwReturn;
  2957. }
  2958. //
  2959. // Function : MachineGuidInFilename
  2960. //
  2961. // Description : Check if the given Machine GUID is in the given filename.
  2962. // Returns TRUE if it is FALSE if it is not.
  2963. //
  2964. /*static*/ BOOL
  2965. MachineGuidInFilename(
  2966. LPWSTR pwszFileName,
  2967. LPWSTR pwszMachineGuid)
  2968. {
  2969. DWORD cbFileName;
  2970. BOOL fRet = FALSE;
  2971. cbFileName = wcslen(pwszFileName);
  2972. // make sure the length of the filename is longer than the GUID
  2973. if (cbFileName >= (DWORD)wcslen(pwszMachineGuid))
  2974. {
  2975. // compare the GUID with the last 36 characters of the file name
  2976. if (0 == memcmp(pwszMachineGuid, &(pwszFileName[cbFileName - 36]),
  2977. 36 * sizeof(WCHAR)))
  2978. fRet = TRUE;
  2979. }
  2980. return fRet;
  2981. }
  2982. DWORD
  2983. GetNextContainer(
  2984. IN DWORD dwProvType,
  2985. IN BOOL fMachineKeyset,
  2986. IN DWORD dwFlags,
  2987. OUT LPSTR pszNextContainer,
  2988. IN OUT DWORD *pcbNextContainer,
  2989. IN OUT HANDLE *phFind)
  2990. {
  2991. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  2992. LPWSTR pwszFilePath = NULL;
  2993. LPWSTR pwszEnumFilePath = NULL;
  2994. WIN32_FIND_DATAW FindData;
  2995. BOOL fIsLocalSystem = FALSE;
  2996. LPWSTR pwszMachineGuid = NULL;
  2997. DWORD dwSts;
  2998. memset(&FindData, 0, sizeof(FindData));
  2999. // get the correct storage area (directory)
  3000. dwSts = GetUserStorageArea(dwProvType, fMachineKeyset, FALSE,
  3001. &fIsLocalSystem, &pwszFilePath);
  3002. if (ERROR_SUCCESS != dwSts)
  3003. {
  3004. dwReturn = dwSts;
  3005. goto ErrorExit;
  3006. }
  3007. if (dwFlags & CRYPT_FIRST)
  3008. {
  3009. *phFind = INVALID_HANDLE_VALUE;
  3010. pwszEnumFilePath = (LPWSTR)ContInfoAlloc((wcslen(pwszFilePath) + 2) * sizeof(WCHAR));
  3011. if (NULL == pwszEnumFilePath)
  3012. {
  3013. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  3014. goto ErrorExit;
  3015. }
  3016. wcscpy(pwszEnumFilePath, pwszFilePath);
  3017. pwszEnumFilePath[wcslen(pwszFilePath)] = '*';
  3018. *phFind = FindFirstFileExW(
  3019. pwszEnumFilePath,
  3020. FindExInfoStandard,
  3021. &FindData,
  3022. FindExSearchNameMatch,
  3023. NULL,
  3024. 0);
  3025. if (INVALID_HANDLE_VALUE == *phFind)
  3026. {
  3027. dwReturn = ERROR_NO_MORE_ITEMS;
  3028. goto ErrorExit;
  3029. }
  3030. // skip past . and ..
  3031. if (!FindNextFileW(*phFind, &FindData))
  3032. {
  3033. dwSts = GetLastError();
  3034. if (ERROR_NO_MORE_FILES == dwSts)
  3035. dwReturn = ERROR_NO_MORE_ITEMS;
  3036. else
  3037. dwReturn = dwSts;
  3038. goto ErrorExit;
  3039. }
  3040. if (!FindNextFileW(*phFind, &FindData))
  3041. {
  3042. dwSts = GetLastError();
  3043. if (ERROR_NO_MORE_FILES == dwSts)
  3044. dwReturn = ERROR_NO_MORE_ITEMS;
  3045. else
  3046. dwReturn = dwSts;
  3047. goto ErrorExit;
  3048. }
  3049. }
  3050. else
  3051. {
  3052. GetNextFile:
  3053. {
  3054. if (!FindNextFileW(*phFind, &FindData))
  3055. {
  3056. dwSts = GetLastError();
  3057. if (ERROR_NO_MORE_FILES == dwSts)
  3058. dwReturn = ERROR_NO_MORE_ITEMS;
  3059. else
  3060. dwReturn = dwSts;
  3061. goto ErrorExit;
  3062. }
  3063. }
  3064. }
  3065. // if this is a machine keyset or this is local system then we want to
  3066. // ignore key containers not matching the current machine GUID
  3067. if (fMachineKeyset || fIsLocalSystem)
  3068. {
  3069. // get the GUID of the machine
  3070. dwSts = GetMachineGUID(&pwszMachineGuid);
  3071. if (ERROR_SUCCESS != dwSts)
  3072. {
  3073. dwReturn = dwSts;
  3074. goto ErrorExit;
  3075. }
  3076. if (NULL == pwszMachineGuid)
  3077. {
  3078. dwReturn = (DWORD)NTE_FAIL;
  3079. goto ErrorExit;
  3080. }
  3081. // check if the file name has the machine GUID
  3082. while (!MachineGuidInFilename(FindData.cFileName, pwszMachineGuid))
  3083. {
  3084. if (!FindNextFileW(*phFind, &FindData))
  3085. {
  3086. dwSts = GetLastError();
  3087. if (ERROR_NO_MORE_FILES == dwSts)
  3088. dwReturn = ERROR_NO_MORE_ITEMS;
  3089. else
  3090. dwReturn = dwSts;
  3091. goto ErrorExit;
  3092. }
  3093. }
  3094. }
  3095. // return the container name, in order to do that we need to open the
  3096. // file and pull out the container name
  3097. //
  3098. // we try to get the next file if failure occurs in case the file was
  3099. // deleted since the FindNextFile
  3100. //
  3101. dwSts = ReadContainerNameFromFile(fMachineKeyset,
  3102. FindData.cFileName,
  3103. pwszFilePath,
  3104. pszNextContainer,
  3105. pcbNextContainer);
  3106. if (ERROR_SUCCESS != dwSts)
  3107. goto GetNextFile;
  3108. else if (ERROR_SUCCESS != dwSts)
  3109. {
  3110. dwReturn = dwSts;
  3111. goto ErrorExit;
  3112. }
  3113. dwReturn = ERROR_SUCCESS;
  3114. ErrorExit:
  3115. if (NULL != pwszMachineGuid)
  3116. ContInfoFree(pwszMachineGuid);
  3117. if (NULL != pwszFilePath)
  3118. ContInfoFree(pwszFilePath);
  3119. if (NULL != pwszEnumFilePath)
  3120. ContInfoFree(pwszEnumFilePath);
  3121. return dwReturn;
  3122. }
  3123. // Converts to UNICODE and uses RegOpenKeyExW
  3124. DWORD
  3125. MyRegOpenKeyEx(
  3126. IN HKEY hRegKey,
  3127. IN LPSTR pszKeyName,
  3128. IN DWORD dwReserved,
  3129. IN REGSAM SAMDesired,
  3130. OUT HKEY *phNewRegKey)
  3131. {
  3132. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  3133. WCHAR rgwchFastBuff[(MAX_PATH + 1) * 2];
  3134. LPWSTR pwsz = NULL;
  3135. BOOL fAlloced = FALSE;
  3136. DWORD cch;
  3137. DWORD dwSts;
  3138. memset(rgwchFastBuff, 0, sizeof(rgwchFastBuff));
  3139. // convert reg key name to unicode
  3140. cch = MultiByteToWideChar(CP_ACP, MB_COMPOSITE,
  3141. pszKeyName, -1,
  3142. NULL, 0);
  3143. if (0 == cch)
  3144. {
  3145. dwReturn = GetLastError();
  3146. goto ErrorExit;
  3147. }
  3148. if ((cch + 1) > ((MAX_PATH + 1) * 2))
  3149. {
  3150. pwsz = ContInfoAlloc((cch + 1) * sizeof(WCHAR));
  3151. if (NULL == pwsz)
  3152. {
  3153. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  3154. goto ErrorExit;
  3155. }
  3156. fAlloced = TRUE;
  3157. }
  3158. else
  3159. {
  3160. pwsz = rgwchFastBuff;
  3161. }
  3162. cch = MultiByteToWideChar(CP_ACP, MB_COMPOSITE,
  3163. pszKeyName, -1, pwsz, cch);
  3164. if (0 == cch)
  3165. {
  3166. dwReturn = GetLastError();
  3167. goto ErrorExit;
  3168. }
  3169. dwSts = RegOpenKeyExW(hRegKey,
  3170. pwsz,
  3171. dwReserved,
  3172. SAMDesired,
  3173. phNewRegKey);
  3174. if (ERROR_SUCCESS != dwSts)
  3175. {
  3176. if (ERROR_FILE_NOT_FOUND == dwSts)
  3177. dwReturn = (DWORD)NTE_BAD_KEYSET;
  3178. else
  3179. dwReturn = dwSts;
  3180. goto ErrorExit;
  3181. }
  3182. dwReturn = ERROR_SUCCESS;
  3183. ErrorExit:
  3184. if (fAlloced && (NULL != pwsz))
  3185. ContInfoFree(pwsz);
  3186. return dwReturn;
  3187. }
  3188. // Converts to UNICODE and uses RegDeleteKeyW
  3189. DWORD
  3190. MyRegDeleteKey(
  3191. IN HKEY hRegKey,
  3192. IN LPSTR pszKeyName)
  3193. {
  3194. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  3195. WCHAR rgwchFastBuff[(MAX_PATH + 1) * 2];
  3196. LPWSTR pwsz = NULL;
  3197. BOOL fAlloced = FALSE;
  3198. DWORD cch;
  3199. DWORD dwSts;
  3200. memset(rgwchFastBuff, 0, sizeof(rgwchFastBuff));
  3201. // convert reg key name to unicode
  3202. cch = MultiByteToWideChar(CP_ACP, MB_COMPOSITE,
  3203. pszKeyName, -1,
  3204. NULL, 0);
  3205. if (0 == cch)
  3206. {
  3207. dwReturn = GetLastError();
  3208. goto ErrorExit;
  3209. }
  3210. if ((cch + 1) > ((MAX_PATH + 1) * 2))
  3211. {
  3212. pwsz = ContInfoAlloc((cch + 1) * sizeof(WCHAR));
  3213. if (NULL == pwsz)
  3214. {
  3215. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  3216. goto ErrorExit;
  3217. }
  3218. fAlloced = TRUE;
  3219. }
  3220. else
  3221. {
  3222. pwsz = rgwchFastBuff;
  3223. }
  3224. cch = MultiByteToWideChar(CP_ACP, MB_COMPOSITE,
  3225. pszKeyName, -1,
  3226. pwsz, cch);
  3227. if (0 == cch)
  3228. {
  3229. dwReturn = GetLastError();
  3230. goto ErrorExit;
  3231. }
  3232. dwSts = RegDeleteKeyW(hRegKey, pwsz);
  3233. if (ERROR_SUCCESS != dwSts)
  3234. {
  3235. dwReturn = dwSts;
  3236. goto ErrorExit;
  3237. }
  3238. dwReturn = ERROR_SUCCESS;
  3239. ErrorExit:
  3240. if (fAlloced && (NULL != pwsz))
  3241. ContInfoFree(pwsz);
  3242. return dwReturn;
  3243. }
  3244. DWORD
  3245. AllocAndSetLocationBuff(
  3246. BOOL fMachineKeySet,
  3247. DWORD dwProvType,
  3248. CONST char *pszUserID,
  3249. HKEY *phTopRegKey,
  3250. TCHAR **ppszLocBuff,
  3251. BOOL fUserKeys,
  3252. BOOL *pfLeaveOldKeys,
  3253. LPDWORD pcbBuff)
  3254. {
  3255. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  3256. DWORD dwSts;
  3257. CHAR szSID[MAX_PATH];
  3258. DWORD cbSID = MAX_PATH;
  3259. DWORD cbLocBuff = 0;
  3260. DWORD cbTmp = 0;
  3261. CHAR *pszTmp;
  3262. BOOL fIsThreadLocalSystem = FALSE;
  3263. if (fMachineKeySet)
  3264. {
  3265. *phTopRegKey = HKEY_LOCAL_MACHINE;
  3266. if ((PROV_RSA_FULL == dwProvType) ||
  3267. (PROV_RSA_SCHANNEL == dwProvType) ||
  3268. (PROV_RSA_AES == dwProvType))
  3269. {
  3270. cbTmp = RSA_MACH_REG_KEY_LOC_LEN;
  3271. pszTmp = RSA_MACH_REG_KEY_LOC;
  3272. }
  3273. else if ((PROV_DSS == dwProvType) ||
  3274. (PROV_DSS_DH == dwProvType) ||
  3275. (PROV_DH_SCHANNEL == dwProvType))
  3276. {
  3277. cbTmp = DSS_MACH_REG_KEY_LOC_LEN;
  3278. pszTmp = DSS_MACH_REG_KEY_LOC;
  3279. }
  3280. else
  3281. {
  3282. dwReturn = (DWORD)NTE_FAIL;
  3283. goto ErrorExit;
  3284. }
  3285. }
  3286. else
  3287. {
  3288. if ((PROV_RSA_FULL == dwProvType) ||
  3289. (PROV_RSA_SCHANNEL == dwProvType) ||
  3290. (PROV_RSA_AES == dwProvType))
  3291. {
  3292. cbTmp = RSA_REG_KEY_LOC_LEN;
  3293. pszTmp = RSA_REG_KEY_LOC;
  3294. }
  3295. else if ((PROV_DSS == dwProvType) ||
  3296. (PROV_DSS_DH == dwProvType) ||
  3297. (PROV_DH_SCHANNEL == dwProvType))
  3298. {
  3299. cbTmp = DSS_REG_KEY_LOC_LEN;
  3300. pszTmp = DSS_REG_KEY_LOC;
  3301. }
  3302. else
  3303. {
  3304. dwReturn = (DWORD)NTE_FAIL;
  3305. goto ErrorExit;
  3306. }
  3307. if (FIsWinNT())
  3308. {
  3309. dwSts = IsThreadLocalSystem(&fIsThreadLocalSystem);
  3310. if (ERROR_SUCCESS != dwSts)
  3311. {
  3312. dwReturn = dwSts;
  3313. goto ErrorExit;
  3314. }
  3315. dwSts = GetUserTextualSidA(szSID, &cbSID);
  3316. if (ERROR_SUCCESS != dwSts)
  3317. {
  3318. dwReturn = dwSts; // NTE_BAD_KEYSET
  3319. goto ErrorExit;
  3320. }
  3321. // this checks to see if the key to the current user may be opened
  3322. if (!fMachineKeySet)
  3323. {
  3324. dwSts = RegOpenKeyEx(HKEY_USERS,
  3325. szSID,
  3326. 0, // dwOptions
  3327. KEY_READ,
  3328. phTopRegKey);
  3329. if (ERROR_SUCCESS != dwSts)
  3330. {
  3331. //
  3332. // if that failed, try HKEY_USERS\.Default (for services on NT).
  3333. //
  3334. cbSID = strlen(".DEFAULT") + 1;
  3335. strcpy(szSID, ".DEFAULT");
  3336. dwSts = RegOpenKeyEx(HKEY_USERS,
  3337. szSID,
  3338. 0, // dwOptions
  3339. KEY_READ,
  3340. phTopRegKey);
  3341. if (ERROR_SUCCESS != dwSts)
  3342. {
  3343. dwReturn = dwSts;
  3344. goto ErrorExit;
  3345. }
  3346. *pfLeaveOldKeys = TRUE;
  3347. }
  3348. }
  3349. }
  3350. else
  3351. {
  3352. *phTopRegKey = HKEY_CURRENT_USER;
  3353. }
  3354. }
  3355. if (!fUserKeys)
  3356. cbLocBuff = strlen(pszUserID);
  3357. cbLocBuff = cbLocBuff + cbTmp + 2;
  3358. *ppszLocBuff = (CHAR*)ContInfoAlloc(cbLocBuff);
  3359. if (NULL == *ppszLocBuff)
  3360. {
  3361. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  3362. goto ErrorExit;
  3363. }
  3364. // Copy the location of the key groups, append the userID to it
  3365. memcpy(*ppszLocBuff, pszTmp, cbTmp);
  3366. if (!fUserKeys)
  3367. {
  3368. (*ppszLocBuff)[cbTmp-1] = '\\';
  3369. strcpy(&(*ppszLocBuff)[cbTmp], pszUserID);
  3370. }
  3371. if (NULL != pcbBuff)
  3372. *pcbBuff = cbLocBuff;
  3373. dwReturn = ERROR_SUCCESS;
  3374. ErrorExit:
  3375. return dwReturn;
  3376. }
  3377. //
  3378. // Enumerates the old machine keys in the file system
  3379. // keys were in this location in Beta 2 and Beta 3 of NT5/Win2K
  3380. //
  3381. DWORD
  3382. EnumOldMachineKeys(
  3383. IN DWORD dwProvType,
  3384. IN OUT PKEY_CONTAINER_INFO pContInfo)
  3385. {
  3386. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  3387. HANDLE hFind = INVALID_HANDLE_VALUE;
  3388. WIN32_FIND_DATAW FindData;
  3389. LPWSTR pwszUserStorageArea = NULL;
  3390. LPWSTR pwszTmp = NULL;
  3391. BOOL fIsLocalSystem;
  3392. DWORD i;
  3393. LPSTR pszNextContainer;
  3394. DWORD cbNextContainer;
  3395. LPSTR pszTmpContainer;
  3396. DWORD dwSts;
  3397. // first check if the enumeration table is already set up
  3398. if (NULL != pContInfo->pchEnumOldMachKeyEntries)
  3399. {
  3400. dwReturn = ERROR_SUCCESS; // Nothing to do!
  3401. goto ErrorExit;
  3402. }
  3403. memset(&FindData, 0, sizeof(FindData));
  3404. dwSts = GetUserStorageArea(dwProvType, TRUE, TRUE,
  3405. &fIsLocalSystem, &pwszUserStorageArea);
  3406. if (ERROR_SUCCESS != dwSts)
  3407. {
  3408. dwReturn = ERROR_NO_MORE_ITEMS;
  3409. goto ErrorExit;
  3410. }
  3411. // last character is backslash, so strip that off
  3412. pwszTmp = (LPWSTR)ContInfoAlloc((wcslen(pwszUserStorageArea) + 3) * sizeof(WCHAR));
  3413. if (NULL == pwszTmp)
  3414. {
  3415. dwSts = ERROR_NOT_ENOUGH_MEMORY;
  3416. goto ErrorExit;
  3417. }
  3418. wcscpy(pwszTmp, pwszUserStorageArea);
  3419. wcscat(pwszTmp, L"*");
  3420. // figure out how many files are in the directroy
  3421. hFind = FindFirstFileExW(pwszTmp,
  3422. FindExInfoStandard,
  3423. &FindData,
  3424. FindExSearchNameMatch,
  3425. NULL,
  3426. 0);
  3427. if (INVALID_HANDLE_VALUE == hFind)
  3428. {
  3429. dwSts = GetLastError();
  3430. if (ERROR_FILE_NOT_FOUND == dwSts)
  3431. dwReturn = ERROR_NO_MORE_ITEMS;
  3432. else
  3433. dwReturn = dwSts;
  3434. goto ErrorExit;
  3435. }
  3436. // skip past . and ..
  3437. if (!FindNextFileW(hFind, &FindData))
  3438. {
  3439. dwSts = GetLastError();
  3440. if (ERROR_NO_MORE_FILES == dwSts)
  3441. dwReturn = ERROR_NO_MORE_ITEMS;
  3442. else
  3443. dwReturn = dwSts;
  3444. goto ErrorExit;
  3445. }
  3446. if (!FindNextFileW(hFind, &FindData))
  3447. {
  3448. dwSts = GetLastError();
  3449. if (ERROR_NO_MORE_FILES == dwSts)
  3450. dwReturn = ERROR_NO_MORE_ITEMS;
  3451. else
  3452. dwReturn = dwSts;
  3453. goto ErrorExit;
  3454. }
  3455. for (i = 1; ; i++)
  3456. {
  3457. memset(&FindData, 0, sizeof(FindData));
  3458. if (!FindNextFileW(hFind, &FindData))
  3459. {
  3460. dwSts = GetLastError();
  3461. if (ERROR_NO_MORE_FILES == dwSts)
  3462. break;
  3463. else if (ERROR_ACCESS_DENIED != dwSts)
  3464. {
  3465. dwReturn = dwSts;
  3466. goto ErrorExit;
  3467. }
  3468. }
  3469. }
  3470. FindClose(hFind);
  3471. hFind = INVALID_HANDLE_VALUE;
  3472. pContInfo->cbOldMachKeyEntry = MAX_PATH + 1;
  3473. pContInfo->dwiOldMachKeyEntry = 0;
  3474. pContInfo->cMaxOldMachKeyEntry = i;
  3475. // allocate space for the file names
  3476. pContInfo->pchEnumOldMachKeyEntries = ContInfoAlloc(i * (MAX_PATH + 1));
  3477. if (NULL == pContInfo->pchEnumOldMachKeyEntries)
  3478. {
  3479. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  3480. goto ErrorExit;
  3481. }
  3482. // enumerate through getting file name from each
  3483. memset(&FindData, 0, sizeof(FindData));
  3484. hFind = FindFirstFileExW(pwszTmp,
  3485. FindExInfoStandard,
  3486. &FindData,
  3487. FindExSearchNameMatch,
  3488. NULL,
  3489. 0);
  3490. if (INVALID_HANDLE_VALUE == hFind)
  3491. {
  3492. dwSts = GetLastError();
  3493. if (ERROR_FILE_NOT_FOUND == dwSts)
  3494. dwReturn = ERROR_NO_MORE_ITEMS;
  3495. else
  3496. dwReturn = dwSts;
  3497. goto ErrorExit;
  3498. }
  3499. // skip past . and ..
  3500. if (!FindNextFileW(hFind, &FindData))
  3501. {
  3502. dwSts = GetLastError();
  3503. if (ERROR_NO_MORE_FILES == dwSts)
  3504. dwReturn = ERROR_NO_MORE_ITEMS;
  3505. else
  3506. dwReturn = dwSts;
  3507. goto ErrorExit;
  3508. }
  3509. memset(&FindData, 0, sizeof(FindData));
  3510. if (!FindNextFileW(hFind, &FindData))
  3511. {
  3512. dwSts = GetLastError();
  3513. if (ERROR_NO_MORE_FILES == dwSts)
  3514. dwReturn = ERROR_NO_MORE_ITEMS;
  3515. else
  3516. dwReturn = dwSts;
  3517. goto ErrorExit;
  3518. }
  3519. pszNextContainer = pContInfo->pchEnumOldMachKeyEntries;
  3520. for (i = 0; i < pContInfo->cMaxOldMachKeyEntry; i++)
  3521. {
  3522. cbNextContainer = MAX_PATH;
  3523. // return the container name, in order to do that we need to open the
  3524. // file and pull out the container name
  3525. dwSts = ReadContainerNameFromFile(TRUE,
  3526. FindData.cFileName,
  3527. pwszUserStorageArea,
  3528. pszNextContainer,
  3529. &cbNextContainer);
  3530. if (ERROR_SUCCESS != dwSts)
  3531. {
  3532. pszTmpContainer = pszNextContainer;
  3533. }
  3534. else
  3535. {
  3536. pszTmpContainer = pszNextContainer + MAX_PATH + 1;
  3537. }
  3538. memset(&FindData, 0, sizeof(FindData));
  3539. if (!FindNextFileW(hFind, &FindData))
  3540. {
  3541. dwSts = GetLastError();
  3542. if (ERROR_NO_MORE_FILES == dwSts)
  3543. break;
  3544. else if (ERROR_ACCESS_DENIED != dwSts)
  3545. {
  3546. dwReturn = dwSts;
  3547. goto ErrorExit;
  3548. }
  3549. }
  3550. pszNextContainer = pszTmpContainer;
  3551. }
  3552. dwReturn = ERROR_SUCCESS;
  3553. ErrorExit:
  3554. if (NULL != pwszTmp)
  3555. ContInfoFree(pwszTmp);
  3556. if (NULL != pwszUserStorageArea)
  3557. ContInfoFree(pwszUserStorageArea);
  3558. if (INVALID_HANDLE_VALUE != hFind)
  3559. FindClose(hFind);
  3560. return dwReturn;
  3561. }
  3562. DWORD
  3563. GetNextEnumedOldMachKeys(
  3564. IN PKEY_CONTAINER_INFO pContInfo,
  3565. IN BOOL fMachineKeyset,
  3566. OUT BYTE *pbData,
  3567. OUT DWORD *pcbData)
  3568. {
  3569. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  3570. CHAR *psz;
  3571. if (!fMachineKeyset)
  3572. {
  3573. dwReturn = ERROR_SUCCESS; // Nothing to do!
  3574. goto ErrorExit;
  3575. }
  3576. if ((NULL == pContInfo->pchEnumOldMachKeyEntries) ||
  3577. (pContInfo->dwiOldMachKeyEntry >= pContInfo->cMaxOldMachKeyEntry))
  3578. {
  3579. dwReturn = ERROR_NO_MORE_ITEMS;
  3580. goto ErrorExit;
  3581. }
  3582. if (NULL == pbData)
  3583. *pcbData = pContInfo->cbRegEntry;
  3584. else if (*pcbData < pContInfo->cbRegEntry)
  3585. {
  3586. *pcbData = pContInfo->cbRegEntry;
  3587. dwReturn = ERROR_MORE_DATA;
  3588. goto ErrorExit;
  3589. }
  3590. else
  3591. {
  3592. psz = pContInfo->pchEnumOldMachKeyEntries + (pContInfo->dwiOldMachKeyEntry *
  3593. pContInfo->cbOldMachKeyEntry);
  3594. memcpy(pbData, psz, strlen(psz) + 1);
  3595. pContInfo->dwiOldMachKeyEntry++;
  3596. }
  3597. dwReturn = ERROR_SUCCESS;
  3598. ErrorExit:
  3599. if (fMachineKeyset)
  3600. *pcbData = pContInfo->cbOldMachKeyEntry;
  3601. return dwReturn;
  3602. }
  3603. //
  3604. // Enumerates the keys in the registry into a list of entries
  3605. //
  3606. DWORD
  3607. EnumRegKeys(
  3608. IN OUT PKEY_CONTAINER_INFO pContInfo,
  3609. IN BOOL fMachineKeySet,
  3610. IN DWORD dwProvType,
  3611. OUT BYTE *pbData,
  3612. IN OUT DWORD *pcbData)
  3613. {
  3614. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  3615. HKEY hTopRegKey = 0;
  3616. LPSTR pszBuff = NULL;
  3617. DWORD cbBuff;
  3618. BOOL fLeaveOldKeys = FALSE;
  3619. HKEY hKey = 0;
  3620. DWORD cSubKeys;
  3621. DWORD cchMaxSubkey;
  3622. DWORD cchMaxClass;
  3623. DWORD cValues;
  3624. DWORD cchMaxValueName;
  3625. DWORD cbMaxValueData;
  3626. DWORD cbSecurityDesriptor;
  3627. FILETIME ftLastWriteTime;
  3628. CHAR *psz;
  3629. DWORD i;
  3630. DWORD dwSts;
  3631. // first check if the enumeration table is already set up
  3632. if (NULL != pContInfo->pchEnumRegEntries)
  3633. {
  3634. dwReturn = ERROR_SUCCESS; // Nothing to do!
  3635. goto ErrorExit;
  3636. }
  3637. // get the path to the registry keys
  3638. dwSts = AllocAndSetLocationBuff(fMachineKeySet,
  3639. dwProvType,
  3640. pContInfo->pszUserName,
  3641. &hTopRegKey,
  3642. &pszBuff,
  3643. TRUE,
  3644. &fLeaveOldKeys,
  3645. &cbBuff);
  3646. if (ERROR_SUCCESS != dwSts)
  3647. {
  3648. dwReturn = dwSts;
  3649. goto ErrorExit;
  3650. }
  3651. // open the reg key
  3652. dwSts = MyRegOpenKeyEx(hTopRegKey,
  3653. pszBuff,
  3654. 0,
  3655. KEY_READ,
  3656. &hKey);
  3657. if (ERROR_SUCCESS != dwSts)
  3658. {
  3659. if (NTE_BAD_KEYSET == dwSts)
  3660. dwReturn = ERROR_NO_MORE_ITEMS;
  3661. else
  3662. dwReturn = dwSts;
  3663. goto ErrorExit;
  3664. }
  3665. // find out info on old key containers
  3666. dwSts = RegQueryInfoKey(hKey,
  3667. NULL,
  3668. NULL,
  3669. NULL,
  3670. &cSubKeys,
  3671. &cchMaxSubkey,
  3672. &cchMaxClass,
  3673. &cValues,
  3674. &cchMaxValueName,
  3675. &cbMaxValueData,
  3676. &cbSecurityDesriptor,
  3677. &ftLastWriteTime);
  3678. if (ERROR_SUCCESS != dwSts)
  3679. {
  3680. dwReturn = dwSts;
  3681. goto ErrorExit;
  3682. }
  3683. // if there are old keys then enumerate them into a table
  3684. if (0 != cSubKeys)
  3685. {
  3686. pContInfo->cMaxRegEntry = cSubKeys;
  3687. pContInfo->cbRegEntry = cchMaxSubkey + 1;
  3688. pContInfo->pchEnumRegEntries =
  3689. ContInfoAlloc(pContInfo->cMaxRegEntry
  3690. * pContInfo->cbRegEntry
  3691. * sizeof(CHAR));
  3692. if (NULL == pContInfo->pchEnumRegEntries)
  3693. {
  3694. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  3695. goto ErrorExit;
  3696. }
  3697. for (i = 0; i < pContInfo->cMaxRegEntry; i++)
  3698. {
  3699. psz = pContInfo->pchEnumRegEntries + (i * pContInfo->cbRegEntry);
  3700. dwSts = RegEnumKey(hKey,
  3701. i,
  3702. psz,
  3703. pContInfo->cbRegEntry);
  3704. if (ERROR_SUCCESS != dwSts)
  3705. {
  3706. dwReturn = dwSts;
  3707. goto ErrorExit;
  3708. }
  3709. }
  3710. if (NULL == pbData)
  3711. *pcbData = pContInfo->cbRegEntry;
  3712. else if (*pcbData < pContInfo->cbRegEntry)
  3713. {
  3714. *pcbData = pContInfo->cbRegEntry;
  3715. dwReturn = ERROR_MORE_DATA;
  3716. goto ErrorExit;
  3717. }
  3718. else
  3719. {
  3720. *pcbData = pContInfo->cbRegEntry;
  3721. // ?BUGBUG? What?
  3722. // CopyMemory(pbData, pContInfo->pbRegEntry, pContInfo->cbRegEntry);
  3723. }
  3724. }
  3725. dwReturn = ERROR_SUCCESS;
  3726. ErrorExit:
  3727. if ((NULL != hTopRegKey)
  3728. && (HKEY_CURRENT_USER != hTopRegKey)
  3729. && (HKEY_LOCAL_MACHINE != hTopRegKey))
  3730. {
  3731. RegCloseKey(hTopRegKey);
  3732. }
  3733. if (NULL != pszBuff)
  3734. ContInfoFree(pszBuff);
  3735. if (NULL != hKey)
  3736. RegCloseKey(hKey);
  3737. return dwReturn;
  3738. }
  3739. DWORD
  3740. GetNextEnumedRegKeys(
  3741. IN PKEY_CONTAINER_INFO pContInfo,
  3742. OUT BYTE *pbData,
  3743. OUT DWORD *pcbData)
  3744. {
  3745. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  3746. CHAR *psz;
  3747. if ((NULL == pContInfo->pchEnumRegEntries) ||
  3748. (pContInfo->dwiRegEntry >= pContInfo->cMaxRegEntry))
  3749. {
  3750. dwReturn = ERROR_NO_MORE_ITEMS;
  3751. goto ErrorExit;
  3752. }
  3753. if (NULL == pbData)
  3754. *pcbData = pContInfo->cbRegEntry;
  3755. else if (*pcbData < pContInfo->cbRegEntry)
  3756. {
  3757. *pcbData = pContInfo->cbRegEntry;
  3758. dwReturn = ERROR_MORE_DATA;
  3759. goto ErrorExit;
  3760. }
  3761. else
  3762. {
  3763. psz = pContInfo->pchEnumRegEntries + (pContInfo->dwiRegEntry *
  3764. pContInfo->cbRegEntry);
  3765. memcpy(pbData, psz, pContInfo->cbRegEntry);
  3766. pContInfo->dwiRegEntry++;
  3767. }
  3768. dwReturn = ERROR_SUCCESS;
  3769. ErrorExit:
  3770. return dwReturn;
  3771. }
  3772. //+ ===========================================================================
  3773. //
  3774. // The function adjusts the token priviledges so that SACL information
  3775. // may be gotten and then opens the indicated registry key. If the token
  3776. // priviledges may be set then the reg key is opened anyway but the
  3777. // flags field will not have the PRIVILEDGE_FOR_SACL value set.
  3778. //
  3779. //- ============================================================================
  3780. DWORD
  3781. OpenRegKeyWithTokenPriviledges(
  3782. IN HKEY hTopRegKey,
  3783. IN LPSTR pszRegKey,
  3784. OUT HKEY *phRegKey,
  3785. OUT DWORD *pdwFlags)
  3786. {
  3787. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  3788. TOKEN_PRIVILEGES tp;
  3789. TOKEN_PRIVILEGES tpPrevious;
  3790. DWORD cbPrevious = sizeof(TOKEN_PRIVILEGES);
  3791. LUID luid;
  3792. HANDLE hToken = 0;
  3793. HKEY hRegKey = 0;
  3794. BOOL fSts;
  3795. BOOL fImpersonating = FALSE;
  3796. BOOL fAdjusted = FALSE;
  3797. DWORD dwAccessFlags = 0;
  3798. DWORD dwSts;
  3799. // check if there is a registry key to open
  3800. dwSts = MyRegOpenKeyEx(hTopRegKey, pszRegKey, 0,
  3801. KEY_ALL_ACCESS, &hRegKey);
  3802. if (ERROR_SUCCESS != dwSts)
  3803. {
  3804. dwReturn = dwSts;
  3805. goto ErrorExit;
  3806. }
  3807. RegCloseKey(hRegKey);
  3808. hRegKey = 0;
  3809. // check if there is a thread token
  3810. fSts = OpenThreadToken(GetCurrentThread(),
  3811. MAXIMUM_ALLOWED, TRUE,
  3812. &hToken);
  3813. if (!fSts)
  3814. {
  3815. if (!ImpersonateSelf(SecurityImpersonation))
  3816. {
  3817. dwReturn = GetLastError();
  3818. goto ErrorExit;
  3819. }
  3820. fImpersonating = TRUE;
  3821. // get the process token
  3822. fSts = OpenThreadToken(GetCurrentThread(),
  3823. MAXIMUM_ALLOWED,
  3824. TRUE,
  3825. &hToken);
  3826. }
  3827. // set up the new priviledge state
  3828. if (fSts)
  3829. {
  3830. memset(&tp, 0, sizeof(tp));
  3831. memset(&tpPrevious, 0, sizeof(tpPrevious));
  3832. fSts = LookupPrivilegeValueA(NULL, SE_SECURITY_NAME, &luid);
  3833. if (fSts)
  3834. {
  3835. //
  3836. // first pass. get current privilege setting
  3837. //
  3838. tp.PrivilegeCount = 1;
  3839. tp.Privileges[0].Luid = luid;
  3840. tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  3841. // adjust privilege
  3842. fSts = AdjustTokenPrivileges(hToken,
  3843. FALSE,
  3844. &tp,
  3845. sizeof(TOKEN_PRIVILEGES),
  3846. &tpPrevious,
  3847. &cbPrevious);
  3848. if (fSts && (ERROR_SUCCESS == GetLastError()))
  3849. {
  3850. fAdjusted = TRUE;
  3851. *pdwFlags |= PRIVILEDGE_FOR_SACL;
  3852. dwAccessFlags = ACCESS_SYSTEM_SECURITY;
  3853. }
  3854. }
  3855. }
  3856. // open the registry key
  3857. dwSts = MyRegOpenKeyEx(hTopRegKey,
  3858. pszRegKey,
  3859. 0,
  3860. KEY_ALL_ACCESS | dwAccessFlags,
  3861. phRegKey);
  3862. if (ERROR_SUCCESS != dwSts)
  3863. {
  3864. dwReturn = dwSts;
  3865. goto ErrorExit;
  3866. }
  3867. dwReturn = ERROR_SUCCESS;
  3868. ErrorExit:
  3869. // now set the privilege back if necessary
  3870. if (fAdjusted)
  3871. {
  3872. // adjust the priviledge and with the previous state
  3873. fSts = AdjustTokenPrivileges(hToken,
  3874. FALSE,
  3875. &tpPrevious,
  3876. sizeof(TOKEN_PRIVILEGES),
  3877. NULL,
  3878. NULL);
  3879. }
  3880. if (NULL != hToken)
  3881. CloseHandle(hToken);
  3882. if (fImpersonating)
  3883. RevertToSelf();
  3884. return dwReturn;
  3885. }
  3886. //+ ===========================================================================
  3887. //
  3888. // The function adjusts the token priviledges so that SACL information
  3889. // may be set on a key container. If the token priviledges may be set
  3890. // indicated by the pUser->dwOldKeyFlags having the PRIVILEDGE_FOR_SACL value set.
  3891. // value set then the token privilege is adjusted before the security
  3892. // descriptor is set on the container. This is needed for the key
  3893. // migration case when keys are being migrated from the registry to files.
  3894. //- ============================================================================
  3895. DWORD
  3896. SetSecurityOnContainerWithTokenPriviledges(
  3897. IN DWORD dwOldKeyFlags,
  3898. IN LPCWSTR wszFileName,
  3899. IN DWORD dwProvType,
  3900. IN DWORD fMachineKeyset,
  3901. IN SECURITY_INFORMATION SecurityInformation,
  3902. IN PSECURITY_DESCRIPTOR pSecurityDescriptor)
  3903. {
  3904. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  3905. TOKEN_PRIVILEGES tp;
  3906. TOKEN_PRIVILEGES tpPrevious;
  3907. DWORD cbPrevious = sizeof(TOKEN_PRIVILEGES);
  3908. LUID luid;
  3909. HANDLE hToken = 0;
  3910. BOOL fStatus;
  3911. BOOL fImpersonating = FALSE;
  3912. BOOL fAdjusted = FALSE;
  3913. DWORD dwSts;
  3914. if (dwOldKeyFlags & PRIVILEDGE_FOR_SACL)
  3915. {
  3916. // check if there is a thread token
  3917. fStatus = OpenThreadToken(GetCurrentThread(),
  3918. MAXIMUM_ALLOWED, TRUE,
  3919. &hToken);
  3920. if (!fStatus)
  3921. {
  3922. if (!ImpersonateSelf(SecurityImpersonation))
  3923. {
  3924. dwReturn = GetLastError();
  3925. goto ErrorExit;
  3926. }
  3927. fImpersonating = TRUE;
  3928. // get the process token
  3929. fStatus = OpenThreadToken(GetCurrentThread(),
  3930. MAXIMUM_ALLOWED,
  3931. TRUE,
  3932. &hToken);
  3933. }
  3934. // set up the new priviledge state
  3935. if (fStatus)
  3936. {
  3937. memset(&tp, 0, sizeof(tp));
  3938. memset(&tpPrevious, 0, sizeof(tpPrevious));
  3939. fStatus = LookupPrivilegeValueA(NULL,
  3940. SE_SECURITY_NAME,
  3941. &luid);
  3942. if (fStatus)
  3943. {
  3944. //
  3945. // first pass. get current privilege setting
  3946. //
  3947. tp.PrivilegeCount = 1;
  3948. tp.Privileges[0].Luid = luid;
  3949. tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  3950. // adjust privilege
  3951. fAdjusted = AdjustTokenPrivileges(hToken,
  3952. FALSE,
  3953. &tp,
  3954. sizeof(TOKEN_PRIVILEGES),
  3955. &tpPrevious,
  3956. &cbPrevious);
  3957. }
  3958. }
  3959. }
  3960. dwSts = SetSecurityOnContainer(wszFileName,
  3961. dwProvType,
  3962. fMachineKeyset,
  3963. SecurityInformation,
  3964. pSecurityDescriptor);
  3965. if (ERROR_SUCCESS != dwSts)
  3966. {
  3967. dwReturn = dwSts;
  3968. goto ErrorExit;
  3969. }
  3970. dwReturn = ERROR_SUCCESS;
  3971. ErrorExit:
  3972. // now set the privilege back if necessary
  3973. // now set the privilege back if necessary
  3974. if (dwOldKeyFlags & PRIVILEDGE_FOR_SACL)
  3975. {
  3976. if (fAdjusted)
  3977. {
  3978. // adjust the priviledge and with the previous state
  3979. fStatus = AdjustTokenPrivileges(hToken,
  3980. FALSE,
  3981. &tpPrevious,
  3982. sizeof(TOKEN_PRIVILEGES),
  3983. NULL,
  3984. NULL);
  3985. }
  3986. }
  3987. if (NULL != hToken)
  3988. CloseHandle(hToken);
  3989. if (fImpersonating)
  3990. RevertToSelf();
  3991. return dwReturn;
  3992. }
  3993. // Loops through the ACEs of an ACL and checks for special access bits
  3994. // for registry keys and converts the access mask so generic access
  3995. // bits are used
  3996. /*static*/ DWORD
  3997. CheckAndChangeAccessMasks(
  3998. IN PACL pAcl)
  3999. {
  4000. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  4001. ACL_SIZE_INFORMATION AclSizeInfo;
  4002. DWORD i;
  4003. ACCESS_ALLOWED_ACE *pAce;
  4004. ACCESS_MASK NewMask;
  4005. memset(&AclSizeInfo, 0, sizeof(AclSizeInfo));
  4006. // get the number of ACEs in the ACL
  4007. if (!GetAclInformation(pAcl, &AclSizeInfo, sizeof(AclSizeInfo),
  4008. AclSizeInformation))
  4009. {
  4010. dwReturn = GetLastError();
  4011. goto ErrorExit;
  4012. }
  4013. // loop through the ACEs checking and changing the access bits
  4014. for (i = 0; i < AclSizeInfo.AceCount; i++)
  4015. {
  4016. if (!GetAce(pAcl, i, &pAce))
  4017. {
  4018. dwReturn = GetLastError();
  4019. goto ErrorExit;
  4020. }
  4021. NewMask = 0;
  4022. // check if the specific access bits are set, if so convert to generic
  4023. if ((pAce->Mask & KEY_QUERY_VALUE) || (pAce->Mask & GENERIC_READ))
  4024. NewMask |= GENERIC_READ;
  4025. if ((pAce->Mask & KEY_SET_VALUE) || (pAce->Mask & GENERIC_ALL) ||
  4026. (pAce->Mask & GENERIC_WRITE))
  4027. {
  4028. NewMask |= GENERIC_ALL;
  4029. }
  4030. pAce->Mask = NewMask;
  4031. }
  4032. dwReturn = ERROR_SUCCESS;
  4033. ErrorExit:
  4034. return dwReturn;
  4035. }
  4036. // Converts a security descriptor from special access to generic access
  4037. /*static*/ DWORD
  4038. ConvertContainerSecurityDescriptor(
  4039. IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
  4040. OUT PSECURITY_DESCRIPTOR *ppNewSD,
  4041. OUT DWORD *pcbNewSD)
  4042. {
  4043. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  4044. DWORD cbSD;
  4045. SECURITY_DESCRIPTOR_CONTROL Control;
  4046. DWORD dwRevision;
  4047. PACL pDacl;
  4048. BOOL fDACLPresent;
  4049. BOOL fDaclDefaulted;
  4050. PACL pSacl;
  4051. BOOL fSACLPresent;
  4052. BOOL fSaclDefaulted;
  4053. DWORD dwSts;
  4054. // ge the control on the security descriptor to check if self relative
  4055. if (!GetSecurityDescriptorControl(pSecurityDescriptor,
  4056. &Control, &dwRevision))
  4057. {
  4058. dwReturn = GetLastError();
  4059. goto ErrorExit;
  4060. }
  4061. // get the length of the security descriptor and alloc space for a copy
  4062. cbSD = GetSecurityDescriptorLength(pSecurityDescriptor);
  4063. *ppNewSD =(PSECURITY_DESCRIPTOR)ContInfoAlloc(cbSD);
  4064. if (NULL == *ppNewSD)
  4065. {
  4066. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  4067. goto ErrorExit;
  4068. }
  4069. if (SE_SELF_RELATIVE & Control)
  4070. {
  4071. // if the Security Descriptor is self relative then make a copy
  4072. memcpy(*ppNewSD, pSecurityDescriptor, cbSD);
  4073. }
  4074. else
  4075. {
  4076. // if not self relative then make a self relative copy
  4077. if (!MakeSelfRelativeSD(pSecurityDescriptor, *ppNewSD, &cbSD))
  4078. {
  4079. dwReturn = GetLastError();
  4080. goto ErrorExit;
  4081. }
  4082. }
  4083. // get the DACL out of the security descriptor
  4084. if (!GetSecurityDescriptorDacl(*ppNewSD, &fDACLPresent, &pDacl,
  4085. &fDaclDefaulted))
  4086. {
  4087. dwReturn = GetLastError();
  4088. goto ErrorExit;
  4089. }
  4090. if (fDACLPresent && pDacl)
  4091. {
  4092. dwSts = CheckAndChangeAccessMasks(pDacl);
  4093. if (ERROR_SUCCESS != dwSts)
  4094. {
  4095. dwReturn = dwSts;
  4096. goto ErrorExit;
  4097. }
  4098. }
  4099. // get the SACL out of the security descriptor
  4100. if (!GetSecurityDescriptorSacl(*ppNewSD, &fSACLPresent, &pSacl,
  4101. &fSaclDefaulted))
  4102. {
  4103. dwReturn = GetLastError();
  4104. goto ErrorExit;
  4105. }
  4106. if (fSACLPresent && pSacl)
  4107. {
  4108. dwSts = CheckAndChangeAccessMasks(pSacl);
  4109. if (ERROR_SUCCESS != dwSts)
  4110. {
  4111. dwReturn = dwSts;
  4112. goto ErrorExit;
  4113. }
  4114. }
  4115. *pcbNewSD = cbSD;
  4116. dwReturn = ERROR_SUCCESS;
  4117. ErrorExit:
  4118. return dwReturn;
  4119. }
  4120. DWORD
  4121. SetSecurityOnContainer(
  4122. IN LPCWSTR wszFileName,
  4123. IN DWORD dwProvType,
  4124. IN DWORD fMachineKeyset,
  4125. IN SECURITY_INFORMATION SecurityInformation,
  4126. IN PSECURITY_DESCRIPTOR pSecurityDescriptor)
  4127. {
  4128. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  4129. PSECURITY_DESCRIPTOR pSD = NULL;
  4130. DWORD cbSD;
  4131. LPWSTR wszFilePath = NULL;
  4132. LPWSTR wszUserStorageArea = NULL;
  4133. DWORD cbUserStorageArea;
  4134. DWORD cbFileName;
  4135. BOOL fIsLocalSystem = FALSE;
  4136. DWORD dwSts;
  4137. dwSts = ConvertContainerSecurityDescriptor(pSecurityDescriptor,
  4138. &pSD, &cbSD);
  4139. if (ERROR_SUCCESS != dwSts)
  4140. {
  4141. dwReturn = dwSts;
  4142. goto ErrorExit;
  4143. }
  4144. // get the correct storage area (directory)
  4145. dwSts = GetUserStorageArea(dwProvType, fMachineKeyset, FALSE,
  4146. &fIsLocalSystem, &wszUserStorageArea);
  4147. if (ERROR_SUCCESS != dwSts)
  4148. {
  4149. dwReturn = dwSts;
  4150. goto ErrorExit;
  4151. }
  4152. cbUserStorageArea = wcslen( wszUserStorageArea ) * sizeof(WCHAR);
  4153. cbFileName = wcslen( wszFileName ) * sizeof(WCHAR);
  4154. wszFilePath = (LPWSTR)ContInfoAlloc(cbUserStorageArea
  4155. + cbFileName
  4156. + sizeof(WCHAR));
  4157. if (wszFilePath == NULL)
  4158. {
  4159. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  4160. goto ErrorExit;
  4161. }
  4162. CopyMemory((BYTE*)wszFilePath, (BYTE*)wszUserStorageArea, cbUserStorageArea);
  4163. CopyMemory((LPBYTE)wszFilePath+cbUserStorageArea, wszFileName, cbFileName + sizeof(WCHAR));
  4164. if (!SetFileSecurityW(wszFilePath, SecurityInformation, pSD))
  4165. {
  4166. dwReturn = GetLastError();
  4167. goto ErrorExit;
  4168. }
  4169. dwReturn = ERROR_SUCCESS;
  4170. ErrorExit:
  4171. if (NULL != pSD)
  4172. ContInfoFree(pSD);
  4173. if (NULL != wszUserStorageArea)
  4174. ContInfoFree(wszUserStorageArea);
  4175. if (NULL != wszFilePath)
  4176. ContInfoFree(wszFilePath);
  4177. return dwReturn;
  4178. }
  4179. DWORD
  4180. GetSecurityOnContainer(
  4181. IN LPCWSTR wszFileName,
  4182. IN DWORD dwProvType,
  4183. IN DWORD fMachineKeyset,
  4184. IN SECURITY_INFORMATION RequestedInformation,
  4185. OUT PSECURITY_DESCRIPTOR pSecurityDescriptor,
  4186. IN OUT DWORD *pcbSecurityDescriptor)
  4187. {
  4188. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  4189. LPWSTR wszFilePath = NULL;
  4190. LPWSTR wszUserStorageArea = NULL;
  4191. DWORD cbUserStorageArea;
  4192. DWORD cbFileName;
  4193. PSECURITY_DESCRIPTOR pSD = NULL;
  4194. DWORD cbSD;
  4195. PSECURITY_DESCRIPTOR pNewSD = NULL;
  4196. DWORD cbNewSD;
  4197. BOOL fIsLocalSystem = FALSE;
  4198. DWORD dwSts;
  4199. // get the correct storage area (directory)
  4200. dwSts = GetUserStorageArea(dwProvType, fMachineKeyset, FALSE,
  4201. &fIsLocalSystem, &wszUserStorageArea);
  4202. if (ERROR_SUCCESS != dwSts)
  4203. {
  4204. dwReturn = dwSts;
  4205. goto ErrorExit;
  4206. }
  4207. cbUserStorageArea = wcslen( wszUserStorageArea ) * sizeof(WCHAR);
  4208. cbFileName = wcslen( wszFileName ) * sizeof(WCHAR);
  4209. wszFilePath = (LPWSTR)ContInfoAlloc(cbUserStorageArea
  4210. + cbFileName
  4211. + sizeof(WCHAR));
  4212. if (wszFilePath == NULL)
  4213. {
  4214. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  4215. goto ErrorExit;
  4216. }
  4217. CopyMemory(wszFilePath, wszUserStorageArea, cbUserStorageArea);
  4218. CopyMemory((LPBYTE)wszFilePath+cbUserStorageArea, wszFileName, cbFileName + sizeof(WCHAR));
  4219. // get the security descriptor on the file
  4220. cbSD = sizeof(cbSD);
  4221. pSD = &cbSD;
  4222. if (!GetFileSecurityW(wszFilePath, RequestedInformation, pSD,
  4223. cbSD, &cbSD))
  4224. {
  4225. dwSts = GetLastError();
  4226. if (ERROR_INSUFFICIENT_BUFFER != dwSts)
  4227. {
  4228. dwReturn = dwSts;
  4229. pSD = NULL;
  4230. goto ErrorExit;
  4231. }
  4232. }
  4233. pSD = (PSECURITY_DESCRIPTOR)ContInfoAlloc(cbSD);
  4234. if (NULL == pSD)
  4235. {
  4236. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  4237. goto ErrorExit;
  4238. }
  4239. if (!GetFileSecurityW(wszFilePath, RequestedInformation, pSD,
  4240. cbSD, &cbSD))
  4241. {
  4242. dwReturn = GetLastError();
  4243. goto ErrorExit;
  4244. }
  4245. // convert the security descriptor from specific to generic
  4246. dwSts = ConvertContainerSecurityDescriptor(pSD, &pNewSD, &cbNewSD);
  4247. if (ERROR_SUCCESS != dwSts)
  4248. {
  4249. dwReturn = dwSts;
  4250. goto ErrorExit;
  4251. }
  4252. if (NULL == pSecurityDescriptor)
  4253. *pcbSecurityDescriptor = cbNewSD;
  4254. else if (*pcbSecurityDescriptor < cbNewSD)
  4255. {
  4256. *pcbSecurityDescriptor = cbNewSD;
  4257. dwReturn = ERROR_MORE_DATA;
  4258. goto ErrorExit;
  4259. }
  4260. else
  4261. {
  4262. *pcbSecurityDescriptor = cbNewSD;
  4263. memcpy(pSecurityDescriptor, pNewSD, *pcbSecurityDescriptor);
  4264. }
  4265. dwReturn = ERROR_SUCCESS;
  4266. ErrorExit:
  4267. if (NULL != pNewSD)
  4268. ContInfoFree(pNewSD);
  4269. if (NULL != pSD)
  4270. ContInfoFree(pSD);
  4271. if (NULL != wszUserStorageArea)
  4272. ContInfoFree(wszUserStorageArea);
  4273. if (NULL != wszFilePath)
  4274. ContInfoFree(wszFilePath);
  4275. return dwReturn;
  4276. }
  4277. //
  4278. // Function : FreeOffloadInfo
  4279. //
  4280. // Description : The function takes a pointer to Offload Information as the
  4281. // first parameter of the call. The function frees the
  4282. // information.
  4283. //
  4284. void
  4285. FreeOffloadInfo(
  4286. IN OUT PEXPO_OFFLOAD_STRUCT pOffloadInfo)
  4287. {
  4288. if (NULL != pOffloadInfo)
  4289. {
  4290. if (NULL != pOffloadInfo->hInst)
  4291. FreeLibrary(pOffloadInfo->hInst);
  4292. ContInfoFree(pOffloadInfo);
  4293. }
  4294. }
  4295. //
  4296. // Function : InitExpOffloadInfo
  4297. //
  4298. // Description : The function takes a pointer to Offload Information as the
  4299. // first parameter of the call. The function checks in the
  4300. // registry to see if an offload module has been registered.
  4301. // If a module is registered then it loads the module
  4302. // and gets the OffloadModExpo function pointer.
  4303. //
  4304. BOOL
  4305. InitExpOffloadInfo(
  4306. IN OUT PEXPO_OFFLOAD_STRUCT *ppOffloadInfo)
  4307. {
  4308. BYTE rgbModule[MAX_PATH + 1];
  4309. BYTE *pbModule = NULL;
  4310. DWORD cbModule;
  4311. BOOL fAlloc = FALSE;
  4312. PEXPO_OFFLOAD_STRUCT pTmpOffloadInfo = NULL;
  4313. HKEY hOffloadRegKey = 0;
  4314. DWORD dwSts;
  4315. BOOL fRet = FALSE;
  4316. // wrap with try/except
  4317. __try
  4318. {
  4319. // check for registration of an offload module
  4320. dwSts = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  4321. "Software\\Microsoft\\Cryptography\\Offload",
  4322. 0, // dwOptions
  4323. KEY_READ,
  4324. &hOffloadRegKey);
  4325. if (ERROR_SUCCESS != dwSts)
  4326. goto ErrorExit;
  4327. // get the name of the offload module
  4328. cbModule = sizeof(rgbModule);
  4329. dwSts = RegQueryValueEx(hOffloadRegKey,
  4330. EXPO_OFFLOAD_REG_VALUE,
  4331. 0, NULL, rgbModule,
  4332. &cbModule);
  4333. if (ERROR_SUCCESS != dwSts)
  4334. {
  4335. if (ERROR_MORE_DATA == dwSts)
  4336. {
  4337. pbModule = (BYTE*)ContInfoAlloc(cbModule);
  4338. if (NULL == pbModule)
  4339. goto ErrorExit;
  4340. fAlloc = TRUE;
  4341. dwSts = RegQueryValueEx(HKEY_LOCAL_MACHINE,
  4342. EXPO_OFFLOAD_REG_VALUE,
  4343. 0, NULL, pbModule,
  4344. &cbModule);
  4345. if (ERROR_SUCCESS != dwSts)
  4346. goto ErrorExit;
  4347. }
  4348. else
  4349. goto ErrorExit;
  4350. }
  4351. else
  4352. pbModule = rgbModule;
  4353. // alloc space for the offload info
  4354. pTmpOffloadInfo = (PEXPO_OFFLOAD_STRUCT)ContInfoAlloc(sizeof(EXPO_OFFLOAD_STRUCT));
  4355. if (NULL == pTmpOffloadInfo)
  4356. goto ErrorExit;
  4357. pTmpOffloadInfo->dwVersion = sizeof(EXPO_OFFLOAD_STRUCT);
  4358. // load the module and get the function pointer
  4359. pTmpOffloadInfo->hInst = LoadLibraryEx((LPTSTR)pbModule, NULL, 0);
  4360. if (NULL == pTmpOffloadInfo->hInst)
  4361. goto ErrorExit;
  4362. pTmpOffloadInfo->pExpoFunc = GetProcAddress(pTmpOffloadInfo->hInst,
  4363. EXPO_OFFLOAD_FUNC_NAME);
  4364. if (NULL == pTmpOffloadInfo->pExpoFunc)
  4365. goto ErrorExit;
  4366. *ppOffloadInfo = pTmpOffloadInfo;
  4367. fRet = TRUE;
  4368. }
  4369. __except (EXCEPTION_EXECUTE_HANDLER)
  4370. {
  4371. goto ErrorExit;
  4372. }
  4373. ErrorExit:
  4374. if (NULL != hOffloadRegKey)
  4375. RegCloseKey(hOffloadRegKey);
  4376. if (fAlloc && (NULL != pbModule))
  4377. ContInfoFree(pbModule);
  4378. if (!fRet)
  4379. FreeOffloadInfo(pTmpOffloadInfo);
  4380. return fRet;
  4381. }
  4382. //
  4383. // Function : ModularExpOffload
  4384. //
  4385. // Description : This function does the offloading of modular exponentiation.
  4386. // The function takes a pointer to Offload Information as the
  4387. // first parameter of the call. If this pointer is not NULL
  4388. // then the function will use this module and call the function.
  4389. // The exponentiation with MOD function will implement
  4390. // Y^X MOD P where Y is the buffer pbBase, X is the buffer
  4391. // pbExpo and P is the buffer pbModulus. The length of the
  4392. // buffer pbExpo is cbExpo and the length of pbBase and
  4393. // pbModulus is cbModulus. The resulting value is output
  4394. // in the pbResult buffer and has length cbModulus.
  4395. // The pReserved and dwFlags parameters are currently ignored.
  4396. // If any of these functions fail then the function fails and
  4397. // returns FALSE. If successful then the function returns
  4398. // TRUE. If the function fails then most likely the caller
  4399. // should fall back to using hard linked modular exponentiation.
  4400. //
  4401. BOOL
  4402. ModularExpOffload(
  4403. IN PEXPO_OFFLOAD_STRUCT pOffloadInfo,
  4404. IN BYTE *pbBase,
  4405. IN BYTE *pbExpo,
  4406. IN DWORD cbExpo,
  4407. IN BYTE *pbModulus,
  4408. IN DWORD cbModulus,
  4409. OUT BYTE *pbResult,
  4410. IN VOID *pReserved,
  4411. IN DWORD dwFlags)
  4412. {
  4413. BOOL fRet = FALSE;
  4414. // wrap with try/except
  4415. __try
  4416. {
  4417. if (NULL == pOffloadInfo)
  4418. goto ErrorExit;
  4419. // call the offload module
  4420. if (!pOffloadInfo->pExpoFunc(pbBase, pbExpo, cbExpo, pbModulus,
  4421. cbModulus, pbResult, pReserved, dwFlags))
  4422. {
  4423. goto ErrorExit;
  4424. }
  4425. fRet = TRUE;
  4426. }
  4427. __except (EXCEPTION_EXECUTE_HANDLER)
  4428. {
  4429. goto ErrorExit;
  4430. }
  4431. ErrorExit:
  4432. return fRet;
  4433. }
  4434. //
  4435. // The following section of code is for the loading and unloading of
  4436. // unicode string resources from a resource DLL (csprc.dll). This
  4437. // allows the resources to be localize even though the CSPs
  4438. // themselves are signed.
  4439. //
  4440. #define MAX_STRING_RSC_SIZE 512
  4441. #define GLOBAL_STRING_BUFFERSIZE_INC 1000
  4442. #define GLOBAL_STRING_BUFFERSIZE 20000
  4443. //
  4444. // Function : FetchString
  4445. //
  4446. // Description : This function gets the specified string resource from
  4447. // the resource DLL, allocates memory for it and copies
  4448. // the string into that memory.
  4449. //
  4450. /*static*/ DWORD
  4451. FetchString(
  4452. HMODULE hModule, // module to get string from
  4453. DWORD dwResourceId, // resource identifier
  4454. LPWSTR *ppString, // target buffer for string
  4455. BYTE **ppStringBlock, // string buffer block
  4456. DWORD *pdwBufferSize, // size of string buffer block
  4457. DWORD *pdwRemainingBufferSize) // remaining size of string buffer block
  4458. {
  4459. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  4460. WCHAR szMessage[MAX_STRING_RSC_SIZE];
  4461. DWORD cchMessage;
  4462. DWORD dwOldSize;
  4463. DWORD dwNewSize;
  4464. LPWSTR pNewStr;
  4465. if (ppStringBlock == NULL || *ppStringBlock == NULL || ppString == NULL)
  4466. {
  4467. dwReturn = ERROR_INVALID_PARAMETER;
  4468. goto ErrorExit;
  4469. }
  4470. cchMessage = LoadStringW(hModule, dwResourceId, szMessage,
  4471. MAX_STRING_RSC_SIZE);
  4472. if (0 == cchMessage)
  4473. {
  4474. dwReturn = GetLastError();
  4475. goto ErrorExit;
  4476. }
  4477. if (*pdwRemainingBufferSize < ((cchMessage + 1) * sizeof(WCHAR)))
  4478. {
  4479. //
  4480. // realloc buffer and update size
  4481. //
  4482. dwOldSize = *pdwBufferSize;
  4483. dwNewSize = dwOldSize + max(GLOBAL_STRING_BUFFERSIZE_INC,
  4484. (((cchMessage + 1) * sizeof(WCHAR)) - *pdwRemainingBufferSize));
  4485. *ppStringBlock = (BYTE*)ContInfoReAlloc(*ppStringBlock, dwNewSize);
  4486. if (NULL == *ppStringBlock)
  4487. {
  4488. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  4489. goto ErrorExit;
  4490. }
  4491. *pdwBufferSize = dwNewSize;
  4492. *pdwRemainingBufferSize += dwNewSize - dwOldSize;
  4493. }
  4494. pNewStr = (LPWSTR)(*ppStringBlock + *pdwBufferSize -
  4495. *pdwRemainingBufferSize);
  4496. // only store the offset just in case a realloc of the entire
  4497. // string buffer needs to be performed at a later time.
  4498. *ppString = (LPWSTR)((BYTE *)pNewStr - (BYTE *)*ppStringBlock);
  4499. wcscpy(pNewStr, szMessage);
  4500. *pdwRemainingBufferSize -= (cchMessage + 1) * sizeof(WCHAR);
  4501. dwReturn = ERROR_SUCCESS;
  4502. ErrorExit:
  4503. return dwReturn;
  4504. }
  4505. DWORD
  4506. LoadStrings(
  4507. void)
  4508. {
  4509. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  4510. HMODULE hMod = 0;
  4511. DWORD dwBufferSize;
  4512. DWORD dwRemainingBufferSize;
  4513. DWORD dwSts;
  4514. if (NULL == l_pbStringBlock)
  4515. {
  4516. hMod = LoadLibraryEx("crypt32.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
  4517. if (NULL == hMod)
  4518. {
  4519. dwReturn = GetLastError();
  4520. goto ErrorExit;
  4521. }
  4522. //
  4523. // get size of all string resources, and then allocate a single block
  4524. // of memory to contain all the strings. This way, we only have to
  4525. // free one block and we benefit memory wise due to locality of reference.
  4526. //
  4527. dwBufferSize = dwRemainingBufferSize = GLOBAL_STRING_BUFFERSIZE;
  4528. l_pbStringBlock = (BYTE*)ContInfoAlloc(dwBufferSize);
  4529. if (NULL == l_pbStringBlock)
  4530. {
  4531. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  4532. goto ErrorExit;
  4533. }
  4534. dwSts = FetchString(hMod, IDS_CSP_RSA_SIG_DESCR, &g_Strings.pwszRSASigDescr,
  4535. &l_pbStringBlock, &dwBufferSize, &dwRemainingBufferSize);
  4536. if (ERROR_SUCCESS != dwSts)
  4537. {
  4538. dwReturn = dwSts;
  4539. goto ErrorExit;
  4540. }
  4541. dwSts = FetchString(hMod, IDS_CSP_RSA_EXCH_DESCR, &g_Strings.pwszRSAExchDescr,
  4542. &l_pbStringBlock, &dwBufferSize, &dwRemainingBufferSize);
  4543. if (ERROR_SUCCESS != dwSts)
  4544. {
  4545. dwReturn = dwSts;
  4546. goto ErrorExit;
  4547. }
  4548. dwSts = FetchString(hMod, IDS_CSP_IMPORT_SIMPLE, &g_Strings.pwszImportSimple,
  4549. &l_pbStringBlock, &dwBufferSize, &dwRemainingBufferSize);
  4550. if (ERROR_SUCCESS != dwSts)
  4551. {
  4552. dwReturn = dwSts;
  4553. goto ErrorExit;
  4554. }
  4555. dwSts = FetchString(hMod, IDS_CSP_SIGNING_E, &g_Strings.pwszSignWExch,
  4556. &l_pbStringBlock, &dwBufferSize, &dwRemainingBufferSize);
  4557. if (ERROR_SUCCESS != dwSts)
  4558. {
  4559. dwReturn = dwSts;
  4560. goto ErrorExit;
  4561. }
  4562. dwSts = FetchString(hMod, IDS_CSP_CREATE_RSA_SIG, &g_Strings.pwszCreateRSASig,
  4563. &l_pbStringBlock, &dwBufferSize, &dwRemainingBufferSize);
  4564. if (ERROR_SUCCESS != dwSts)
  4565. {
  4566. dwReturn = dwSts;
  4567. goto ErrorExit;
  4568. }
  4569. dwSts = FetchString(hMod, IDS_CSP_CREATE_RSA_EXCH, &g_Strings.pwszCreateRSAExch,
  4570. &l_pbStringBlock, &dwBufferSize, &dwRemainingBufferSize);
  4571. if (ERROR_SUCCESS != dwSts)
  4572. {
  4573. dwReturn = dwSts;
  4574. goto ErrorExit;
  4575. }
  4576. dwSts = FetchString(hMod, IDS_CSP_DSS_SIG_DESCR, &g_Strings.pwszDSSSigDescr,
  4577. &l_pbStringBlock, &dwBufferSize, &dwRemainingBufferSize);
  4578. if (ERROR_SUCCESS != dwSts)
  4579. {
  4580. dwReturn = dwSts;
  4581. goto ErrorExit;
  4582. }
  4583. dwSts = FetchString(hMod, IDS_CSP_DSS_EXCH_DESCR, &g_Strings.pwszDHExchDescr,
  4584. &l_pbStringBlock, &dwBufferSize, &dwRemainingBufferSize);
  4585. if (ERROR_SUCCESS != dwSts)
  4586. {
  4587. dwReturn = dwSts;
  4588. goto ErrorExit;
  4589. }
  4590. dwSts = FetchString(hMod, IDS_CSP_CREATE_DSS_SIG, &g_Strings.pwszCreateDSS,
  4591. &l_pbStringBlock, &dwBufferSize, &dwRemainingBufferSize);
  4592. if (ERROR_SUCCESS != dwSts)
  4593. {
  4594. dwReturn = dwSts;
  4595. goto ErrorExit;
  4596. }
  4597. dwSts = FetchString(hMod, IDS_CSP_CREATE_DH_EXCH, &g_Strings.pwszCreateDH,
  4598. &l_pbStringBlock, &dwBufferSize, &dwRemainingBufferSize);
  4599. if (ERROR_SUCCESS != dwSts)
  4600. {
  4601. dwReturn = dwSts;
  4602. goto ErrorExit;
  4603. }
  4604. dwSts = FetchString(hMod, IDS_CSP_IMPORT_E_PUB, &g_Strings.pwszImportDHPub,
  4605. &l_pbStringBlock, &dwBufferSize, &dwRemainingBufferSize);
  4606. if (ERROR_SUCCESS != dwSts)
  4607. {
  4608. dwReturn = dwSts;
  4609. goto ErrorExit;
  4610. }
  4611. dwSts = FetchString(hMod, IDS_CSP_MIGR, &g_Strings.pwszMigrKeys,
  4612. &l_pbStringBlock, &dwBufferSize, &dwRemainingBufferSize);
  4613. if (ERROR_SUCCESS != dwSts)
  4614. {
  4615. dwReturn = dwSts;
  4616. goto ErrorExit;
  4617. }
  4618. dwSts = FetchString(hMod, IDS_CSP_DELETE_SIG, &g_Strings.pwszDeleteSig,
  4619. &l_pbStringBlock, &dwBufferSize, &dwRemainingBufferSize);
  4620. if (ERROR_SUCCESS != dwSts)
  4621. {
  4622. dwReturn = dwSts;
  4623. goto ErrorExit;
  4624. }
  4625. dwSts = FetchString(hMod, IDS_CSP_DELETE_KEYX, &g_Strings.pwszDeleteExch,
  4626. &l_pbStringBlock, &dwBufferSize, &dwRemainingBufferSize);
  4627. if (ERROR_SUCCESS != dwSts)
  4628. {
  4629. dwReturn = dwSts;
  4630. goto ErrorExit;
  4631. }
  4632. dwSts = FetchString(hMod, IDS_CSP_DELETE_SIG_MIGR, &g_Strings.pwszDeleteMigrSig,
  4633. &l_pbStringBlock, &dwBufferSize, &dwRemainingBufferSize);
  4634. if (ERROR_SUCCESS != dwSts)
  4635. {
  4636. dwReturn = dwSts;
  4637. goto ErrorExit;
  4638. }
  4639. dwSts = FetchString(hMod, IDS_CSP_DELETE_KEYX_MIGR, &g_Strings.pwszDeleteMigrExch,
  4640. &l_pbStringBlock, &dwBufferSize, &dwRemainingBufferSize);
  4641. if (ERROR_SUCCESS != dwSts)
  4642. {
  4643. dwReturn = dwSts;
  4644. goto ErrorExit;
  4645. }
  4646. dwSts = FetchString(hMod, IDS_CSP_SIGNING_S, &g_Strings.pwszSigning,
  4647. &l_pbStringBlock, &dwBufferSize, &dwRemainingBufferSize);
  4648. if (ERROR_SUCCESS != dwSts)
  4649. {
  4650. dwReturn = dwSts;
  4651. goto ErrorExit;
  4652. }
  4653. dwSts = FetchString(hMod, IDS_CSP_EXPORT_E_PRIV, &g_Strings.pwszExportPrivExch,
  4654. &l_pbStringBlock, &dwBufferSize, &dwRemainingBufferSize);
  4655. if (ERROR_SUCCESS != dwSts)
  4656. {
  4657. dwReturn = dwSts;
  4658. goto ErrorExit;
  4659. }
  4660. dwSts = FetchString(hMod, IDS_CSP_EXPORT_S_PRIV, &g_Strings.pwszExportPrivSig,
  4661. &l_pbStringBlock, &dwBufferSize, &dwRemainingBufferSize);
  4662. if (ERROR_SUCCESS != dwSts)
  4663. {
  4664. dwReturn = dwSts;
  4665. goto ErrorExit;
  4666. }
  4667. dwSts = FetchString(hMod, IDS_CSP_IMPORT_E_PRIV, &g_Strings.pwszImportPrivExch,
  4668. &l_pbStringBlock, &dwBufferSize, &dwRemainingBufferSize);
  4669. if (ERROR_SUCCESS != dwSts)
  4670. {
  4671. dwReturn = dwSts;
  4672. goto ErrorExit;
  4673. }
  4674. dwSts = FetchString(hMod, IDS_CSP_IMPORT_S_PRIV, &g_Strings.pwszImportPrivSig,
  4675. &l_pbStringBlock, &dwBufferSize, &dwRemainingBufferSize);
  4676. if (ERROR_SUCCESS != dwSts)
  4677. {
  4678. dwReturn = dwSts;
  4679. goto ErrorExit;
  4680. }
  4681. dwSts = FetchString(hMod, IDS_CSP_AUDIT_CAPI_KEY, &g_Strings.pwszAuditCapiKey,
  4682. &l_pbStringBlock, &dwBufferSize, &dwRemainingBufferSize);
  4683. if (ERROR_SUCCESS != dwSts)
  4684. {
  4685. dwReturn = dwSts;
  4686. goto ErrorExit;
  4687. }
  4688. // Fix up all the strings to be real pointers rather than offsets.
  4689. // the reason that offsets are originally stored is because we may
  4690. // need to reallocate the buffer that all the strings are stored in.
  4691. // So offsets are stored so that the pointers for those strings in
  4692. // the buffers don't become invalid.
  4693. g_Strings.pwszRSASigDescr = (LPWSTR)(((ULONG_PTR) g_Strings.pwszRSASigDescr) + l_pbStringBlock);
  4694. g_Strings.pwszRSAExchDescr = (LPWSTR)(((ULONG_PTR) g_Strings.pwszRSAExchDescr) + l_pbStringBlock);
  4695. g_Strings.pwszImportSimple = (LPWSTR)(((ULONG_PTR) g_Strings.pwszImportSimple) + l_pbStringBlock);
  4696. g_Strings.pwszSignWExch = (LPWSTR)(((ULONG_PTR) g_Strings.pwszSignWExch) + l_pbStringBlock);
  4697. g_Strings.pwszCreateRSASig = (LPWSTR)(((ULONG_PTR) g_Strings.pwszCreateRSASig) + l_pbStringBlock);
  4698. g_Strings.pwszCreateRSAExch = (LPWSTR)(((ULONG_PTR) g_Strings.pwszCreateRSAExch) + l_pbStringBlock);
  4699. g_Strings.pwszDSSSigDescr = (LPWSTR)(((ULONG_PTR) g_Strings.pwszDSSSigDescr) + l_pbStringBlock);
  4700. g_Strings.pwszDHExchDescr = (LPWSTR)(((ULONG_PTR) g_Strings.pwszDHExchDescr) + l_pbStringBlock);
  4701. g_Strings.pwszCreateDSS = (LPWSTR)(((ULONG_PTR) g_Strings.pwszCreateDSS) + l_pbStringBlock);
  4702. g_Strings.pwszCreateDH = (LPWSTR)(((ULONG_PTR) g_Strings.pwszCreateDH) + l_pbStringBlock);
  4703. g_Strings.pwszImportDHPub = (LPWSTR)(((ULONG_PTR) g_Strings.pwszImportDHPub) + l_pbStringBlock);
  4704. g_Strings.pwszMigrKeys = (LPWSTR)(((ULONG_PTR) g_Strings.pwszMigrKeys) + l_pbStringBlock);
  4705. g_Strings.pwszDeleteSig = (LPWSTR)(((ULONG_PTR) g_Strings.pwszDeleteSig) + l_pbStringBlock);
  4706. g_Strings.pwszDeleteExch = (LPWSTR)(((ULONG_PTR) g_Strings.pwszDeleteExch) + l_pbStringBlock);
  4707. g_Strings.pwszDeleteMigrSig = (LPWSTR)(((ULONG_PTR) g_Strings.pwszDeleteMigrSig) + l_pbStringBlock);
  4708. g_Strings.pwszDeleteMigrExch = (LPWSTR)(((ULONG_PTR) g_Strings.pwszDeleteMigrExch) + l_pbStringBlock);
  4709. g_Strings.pwszSigning = (LPWSTR)(((ULONG_PTR) g_Strings.pwszSigning) + l_pbStringBlock);
  4710. g_Strings.pwszExportPrivExch = (LPWSTR)(((ULONG_PTR) g_Strings.pwszExportPrivExch) + l_pbStringBlock);
  4711. g_Strings.pwszExportPrivSig = (LPWSTR)(((ULONG_PTR) g_Strings.pwszExportPrivSig) + l_pbStringBlock);
  4712. g_Strings.pwszImportPrivExch = (LPWSTR)(((ULONG_PTR) g_Strings.pwszImportPrivExch) + l_pbStringBlock);
  4713. g_Strings.pwszImportPrivSig = (LPWSTR)(((ULONG_PTR) g_Strings.pwszImportPrivSig) + l_pbStringBlock);
  4714. g_Strings.pwszAuditCapiKey = (LPWSTR)(((ULONG_PTR) g_Strings.pwszAuditCapiKey) + l_pbStringBlock);
  4715. FreeLibrary(hMod);
  4716. hMod = NULL;
  4717. }
  4718. return ERROR_SUCCESS;
  4719. ErrorExit:
  4720. if (NULL != l_pbStringBlock)
  4721. {
  4722. ContInfoFree(l_pbStringBlock);
  4723. l_pbStringBlock = NULL;
  4724. }
  4725. if (hMod)
  4726. FreeLibrary(hMod);
  4727. return dwReturn;
  4728. }
  4729. void
  4730. UnloadStrings(
  4731. void)
  4732. {
  4733. if (NULL != l_pbStringBlock)
  4734. {
  4735. ContInfoFree(l_pbStringBlock);
  4736. l_pbStringBlock = NULL;
  4737. memset(&g_Strings, 0, sizeof(g_Strings));
  4738. }
  4739. }
  4740. #ifdef USE_HW_RNG
  4741. #ifdef _M_IX86
  4742. // stuff for INTEL RNG usage
  4743. //
  4744. // Function : GetRNGDriverHandle
  4745. //
  4746. // Description : Gets the handle to the INTEL RNG driver if available, then
  4747. // checks if the chipset supports the hardware RNG. If so
  4748. // the previous driver handle is closed if necessary and the
  4749. // new handle is assigned to the passed in parameter.
  4750. //
  4751. DWORD
  4752. GetRNGDriverHandle(
  4753. IN OUT HANDLE *phDriver)
  4754. {
  4755. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  4756. ISD_Capability ISD_Cap; //in/out for GetCapability
  4757. DWORD dwBytesReturned;
  4758. char szDeviceName[80] = ""; //Name of device
  4759. HANDLE hDriver = INVALID_HANDLE_VALUE; //Driver handle
  4760. BOOL fReturnCode; //Return code from IOCTL call
  4761. memset(&ISD_Cap, 0, sizeof(ISD_Cap));
  4762. wsprintf(szDeviceName,"\\\\.\\"DRIVER_NAME);
  4763. hDriver = CreateFileA(szDeviceName,
  4764. FILE_SHARE_READ | FILE_SHARE_WRITE
  4765. | GENERIC_READ | GENERIC_WRITE,
  4766. 0, NULL,
  4767. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  4768. if (INVALID_HANDLE_VALUE == hDriver)
  4769. {
  4770. dwReturn = GetLastError();
  4771. goto ErrorExit;
  4772. }
  4773. //Get RNG Enabled
  4774. ISD_Cap.uiIndex = ISD_RNG_ENABLED; //Set input member
  4775. fReturnCode = DeviceIoControl(hDriver,
  4776. IOCTL_ISD_GetCapability,
  4777. &ISD_Cap, sizeof(ISD_Cap),
  4778. &ISD_Cap, sizeof(ISD_Cap),
  4779. &dwBytesReturned,
  4780. NULL);
  4781. if (fReturnCode == FALSE || ISD_Cap.iStatus != ISD_EOK)
  4782. {
  4783. dwReturn = GetLastError();
  4784. goto ErrorExit;
  4785. }
  4786. // close the previous handle if already there
  4787. if (INVALID_HANDLE_VALUE != *phDriver)
  4788. CloseHandle(*phDriver);
  4789. *phDriver = hDriver;
  4790. return ERROR_SUCCESS;
  4791. ErrorExit:
  4792. if (INVALID_HANDLE_VALUE != hDriver)
  4793. CloseHandle(hDriver);
  4794. return dwReturn;
  4795. }
  4796. //
  4797. // Function : CheckIfRNGAvailable
  4798. //
  4799. // Description : Checks if the INTEL RNG driver is available, if so then
  4800. // checks if the chipset supports the hardware RNG.
  4801. //
  4802. DWORD
  4803. CheckIfRNGAvailable(
  4804. void)
  4805. {
  4806. HANDLE hDriver = INVALID_HANDLE_VALUE; //Driver handle
  4807. DWORD dwSts;
  4808. dwSts = GetRNGDriverHandle(&hDriver);
  4809. if (ERROR_SUCCESS == dwSts)
  4810. CloseHandle(hDriver);
  4811. return dwSts;
  4812. }
  4813. //
  4814. // Function : HWRNGGenRandom
  4815. //
  4816. // Description : Uses the passed in handle to the INTEL RNG driver
  4817. // to fill the buffer with random bits. Actually uses
  4818. // XOR to fill the buffer so that the passed in buffer
  4819. // is also mixed in.
  4820. //
  4821. DWORD
  4822. HWRNGGenRandom(
  4823. IN HANDLE hRNGDriver,
  4824. IN OUT BYTE *pbBuffer,
  4825. IN DWORD dwLen)
  4826. {
  4827. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  4828. ISD_RandomNumber ISD_Random; //in/out for GetRandomNumber
  4829. DWORD dwBytesReturned = 0;
  4830. DWORD i;
  4831. DWORD *pdw;
  4832. BYTE *pb;
  4833. BYTE *pbRand;
  4834. BOOL fReturnCode; //Return code from IOCTL call
  4835. memset(&ISD_Random, 0, sizeof(ISD_Random));
  4836. for (i = 0; i < (dwLen / sizeof(DWORD)); i++)
  4837. {
  4838. pdw = (DWORD*)(pbBuffer + i * sizeof(DWORD));
  4839. //No input needed in the ISD_Random structure for this operation,
  4840. //so just send it in as is.
  4841. fReturnCode = DeviceIoControl(hRNGDriver,
  4842. IOCTL_ISD_GetRandomNumber,
  4843. &ISD_Random, sizeof(ISD_Random),
  4844. &ISD_Random, sizeof(ISD_Random),
  4845. &dwBytesReturned,
  4846. NULL);
  4847. if (fReturnCode == 0 || ISD_Random.iStatus != ISD_EOK)
  4848. {
  4849. //Error - ignore the data returned
  4850. dwReturn = GetLastError();
  4851. goto ErrorExit;
  4852. }
  4853. *pdw = *pdw ^ ISD_Random.uiRandomNum;
  4854. }
  4855. pb = pbBuffer + i * sizeof(DWORD);
  4856. fReturnCode = DeviceIoControl(hRNGDriver,
  4857. IOCTL_ISD_GetRandomNumber,
  4858. &ISD_Random, sizeof(ISD_Random),
  4859. &ISD_Random, sizeof(ISD_Random),
  4860. &dwBytesReturned,
  4861. NULL);
  4862. if (fReturnCode == 0 || ISD_Random.iStatus != ISD_EOK)
  4863. {
  4864. //Error - ignore the data returned
  4865. dwReturn = GetLastError();
  4866. goto ErrorExit;
  4867. }
  4868. pbRand = (BYTE*)&ISD_Random.uiRandomNum;
  4869. for (i = 0; i < (dwLen % sizeof(DWORD)); i++)
  4870. pb[i] ^= pbRand[i];
  4871. dwReturn = ERROR_SUCCESS;
  4872. ErrorExit:
  4873. return dwReturn;
  4874. }
  4875. #ifdef TEST_HW_RNG
  4876. //
  4877. // Function : SetupHWRNGIfRegistered
  4878. //
  4879. // Description : Checks if there is a registry setting indicating the HW RNG
  4880. // is to be used. If the registry entry is there then it attempts
  4881. // to get the HW RNG driver handle.
  4882. //
  4883. DWORD
  4884. SetupHWRNGIfRegistered(
  4885. OUT HANDLE *phRNGDriver)
  4886. {
  4887. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  4888. DWORD dwSts;
  4889. HKEY hRegKey = NULL;
  4890. // first check the registry entry to see if supposed to use HW RNG
  4891. dwSts = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  4892. "Software\\Microsoft\\Cryptography\\UseHWRNG",
  4893. 0, // dwOptions
  4894. KEY_READ,
  4895. &hRegKey);
  4896. if (ERROR_SUCCESS == dwSts)
  4897. {
  4898. // get the driver handle
  4899. dwSts = GetRNGDriverHandle(phRNGDriver);
  4900. if (ERROR_SUCCESS != dwSts)
  4901. {
  4902. dwReturn = dwSts;
  4903. goto ErrorExit;
  4904. }
  4905. }
  4906. dwReturn = ERROR_SUCCESS;
  4907. ErrorExit:
  4908. if (NULL != hRegKey)
  4909. RegCloseKey(hRegKey);
  4910. return dwReturn;
  4911. }
  4912. #endif // TEST_HW_RNG
  4913. #endif // _M_IX86
  4914. #endif // USE_HW_RNG
  4915. // The function MACs the given bytes.
  4916. /*static*/ void
  4917. MACBytes(
  4918. IN DESTable *pDESKeyTable,
  4919. IN BYTE *pbData,
  4920. IN DWORD cbData,
  4921. IN OUT BYTE *pbTmp,
  4922. IN OUT DWORD *pcbTmp,
  4923. IN OUT BYTE *pbMAC)
  4924. {
  4925. DWORD cb = cbData;
  4926. DWORD cbMACed = 0;
  4927. while (cb)
  4928. {
  4929. if ((cb + *pcbTmp) < DES_BLOCKLEN)
  4930. {
  4931. memcpy(pbTmp + *pcbTmp, pbData + cbMACed, cb);
  4932. *pcbTmp += cb;
  4933. break;
  4934. }
  4935. else
  4936. {
  4937. memcpy(pbTmp + *pcbTmp, pbData + cbMACed, DES_BLOCKLEN - *pcbTmp);
  4938. CBC(des, DES_BLOCKLEN, pbMAC, pbTmp, pDESKeyTable,
  4939. ENCRYPT, pbMAC);
  4940. cbMACed = cbMACed + (DES_BLOCKLEN - *pcbTmp);
  4941. cb = cb - (DES_BLOCKLEN - *pcbTmp);
  4942. *pcbTmp = 0;
  4943. }
  4944. }
  4945. }
  4946. // Given hInst, allocs and returns pointers to MAC pulled from
  4947. // resource
  4948. /*static*/ DWORD
  4949. GetResourcePtr(
  4950. IN HMODULE hInst,
  4951. IN LPSTR pszRsrcName,
  4952. OUT BYTE **ppbRsrcMAC,
  4953. OUT DWORD *pcbRsrcMAC)
  4954. {
  4955. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  4956. HRSRC hRsrc;
  4957. // Nab resource handle for our signature
  4958. hRsrc = FindResourceA(hInst, pszRsrcName, RT_RCDATA);
  4959. if (NULL == hRsrc)
  4960. {
  4961. dwReturn = GetLastError();
  4962. goto ErrorExit;
  4963. }
  4964. // get a pointer to the actual signature data
  4965. *ppbRsrcMAC = (PBYTE)LoadResource(hInst, hRsrc);
  4966. if (NULL == *ppbRsrcMAC)
  4967. {
  4968. dwReturn = GetLastError();
  4969. goto ErrorExit;
  4970. }
  4971. // determine the size of the resource
  4972. *pcbRsrcMAC = SizeofResource(hInst, hRsrc);
  4973. if (0 == *pcbRsrcMAC)
  4974. {
  4975. dwReturn = GetLastError();
  4976. goto ErrorExit;
  4977. }
  4978. dwReturn = ERROR_SUCCESS;
  4979. ErrorExit:
  4980. return dwReturn;
  4981. }
  4982. #define CSP_TO_BE_MACED_CHUNK 4096
  4983. // Given hFile, reads the specified number of bytes (cbToBeMACed) from the file
  4984. // and MACs these bytes. The function does this in chunks.
  4985. /*static*/ DWORD
  4986. MACBytesOfFile(
  4987. IN HANDLE hFile,
  4988. IN DWORD cbToBeMACed,
  4989. IN DESTable *pDESKeyTable,
  4990. IN BYTE *pbTmp,
  4991. IN DWORD *pcbTmp,
  4992. IN BYTE *pbMAC)
  4993. {
  4994. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  4995. BYTE rgbChunk[CSP_TO_BE_MACED_CHUNK];
  4996. DWORD cbRemaining = cbToBeMACed;
  4997. DWORD cbToRead;
  4998. DWORD dwBytesRead;
  4999. //
  5000. // loop over the file for the specified number of bytes
  5001. // updating the hash as we go.
  5002. //
  5003. while (cbRemaining > 0)
  5004. {
  5005. if (cbRemaining < CSP_TO_BE_MACED_CHUNK)
  5006. cbToRead = cbRemaining;
  5007. else
  5008. cbToRead = CSP_TO_BE_MACED_CHUNK;
  5009. if (!ReadFile(hFile, rgbChunk, cbToRead, &dwBytesRead, NULL))
  5010. {
  5011. dwReturn = GetLastError();
  5012. goto ErrorExit;
  5013. }
  5014. MACBytes(pDESKeyTable, rgbChunk, dwBytesRead, pbTmp, pcbTmp,
  5015. pbMAC);
  5016. cbRemaining -= cbToRead;
  5017. }
  5018. dwReturn = ERROR_SUCCESS;
  5019. ErrorExit:
  5020. return dwReturn;
  5021. }
  5022. /*static*/ DWORD
  5023. MACTheFile(
  5024. LPCSTR pszImage,
  5025. DWORD cbImage)
  5026. {
  5027. static CONST BYTE rgbMACDESKey[]
  5028. = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
  5029. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  5030. HMODULE hInst;
  5031. MEMORY_BASIC_INFORMATION MemInfo;
  5032. BYTE *pbRsrcMAC;
  5033. DWORD cbRsrcMAC;
  5034. BYTE *pbRsrcSig;
  5035. DWORD cbRsrcSig;
  5036. BYTE *pbStart = NULL;
  5037. BYTE rgbMAC[DES_BLOCKLEN];
  5038. BYTE rgbZeroMAC[DES_BLOCKLEN + sizeof(DWORD) * 2];
  5039. BYTE rgbZeroSig[144];
  5040. BYTE *pbPostCRC; // pointer to just after CRC
  5041. DWORD cbCRCToRsrc1; // number of bytes from CRC to first rsrc
  5042. DWORD cbRsrc1ToRsrc2; // number of bytes from first rsrc to second
  5043. DWORD cbPostRsrc; // size - (already hashed + signature size)
  5044. BYTE *pbRsrc1ToRsrc2;
  5045. BYTE *pbPostRsrc;
  5046. BYTE *pbZeroRsrc1;
  5047. BYTE *pbZeroRsrc2;
  5048. DWORD cbZeroRsrc1;
  5049. DWORD cbZeroRsrc2;
  5050. DWORD *pdwMACInFileVer;
  5051. DWORD *pdwCRCOffset;
  5052. DWORD dwCRCOffset;
  5053. DWORD dwZeroCRC = 0;
  5054. OFSTRUCT ImageInfoBuf;
  5055. HFILE hFile = HFILE_ERROR;
  5056. HANDLE hMapping = NULL;
  5057. DESTable DESKeyTable;
  5058. BYTE rgbTmp[DES_BLOCKLEN];
  5059. DWORD cbTmp = 0;
  5060. DWORD dwSts;
  5061. memset(&MemInfo, 0, sizeof(MemInfo));
  5062. memset(rgbMAC, 0, sizeof(rgbMAC));
  5063. memset(rgbTmp, 0, sizeof(rgbTmp));
  5064. // Load the file
  5065. hFile = OpenFile(pszImage, &ImageInfoBuf, OF_READ);
  5066. if (HFILE_ERROR == hFile)
  5067. {
  5068. dwReturn = GetLastError();
  5069. goto ErrorExit;
  5070. }
  5071. hMapping = CreateFileMapping((HANDLE)IntToPtr(hFile),
  5072. NULL,
  5073. PAGE_READONLY,
  5074. 0,
  5075. 0,
  5076. NULL);
  5077. if (hMapping == NULL)
  5078. {
  5079. dwReturn = GetLastError();
  5080. goto ErrorExit;
  5081. }
  5082. pbStart = MapViewOfFile(hMapping,
  5083. FILE_MAP_READ,
  5084. 0,
  5085. 0,
  5086. 0);
  5087. if (pbStart == NULL)
  5088. {
  5089. dwReturn = GetLastError();
  5090. goto ErrorExit;
  5091. }
  5092. // Convert pointer to HMODULE, using the same scheme as
  5093. // LoadLibrary (windows\base\client\module.c).
  5094. hInst = (HMODULE)((ULONG_PTR)pbStart | 0x00000001);
  5095. // the MAC resource
  5096. dwSts = GetResourcePtr(hInst, CRYPT_MAC_RESOURCE, &pbRsrcMAC, &cbRsrcMAC);
  5097. if (ERROR_SUCCESS != dwSts)
  5098. {
  5099. dwReturn = dwSts;
  5100. goto ErrorExit;
  5101. }
  5102. // the SIG resource
  5103. dwSts = GetResourcePtr(hInst, CRYPT_SIG_RESOURCE, &pbRsrcSig, &cbRsrcSig);
  5104. if (ERROR_SUCCESS != dwSts)
  5105. {
  5106. dwReturn = dwSts;
  5107. goto ErrorExit;
  5108. }
  5109. if (cbRsrcMAC < (sizeof(DWORD) * 2))
  5110. {
  5111. dwReturn = (DWORD)NTE_FAIL;
  5112. goto ErrorExit;
  5113. }
  5114. // create a zero byte MAC
  5115. memset(rgbZeroMAC, 0, sizeof(rgbZeroMAC));
  5116. // check the sig in file version and get the CRC offset
  5117. pdwMACInFileVer = (DWORD*)pbRsrcMAC;
  5118. pdwCRCOffset = (DWORD*)(pbRsrcMAC + sizeof(DWORD));
  5119. dwCRCOffset = *pdwCRCOffset;
  5120. if ((0x00000100 != *pdwMACInFileVer) || (dwCRCOffset > cbImage))
  5121. {
  5122. dwReturn = (DWORD)NTE_FAIL;
  5123. goto ErrorExit;
  5124. }
  5125. if (DES_BLOCKLEN != (cbRsrcMAC - (sizeof(DWORD) * 2)))
  5126. {
  5127. dwReturn = (DWORD)NTE_FAIL;
  5128. goto ErrorExit;
  5129. }
  5130. // create a zero byte Sig
  5131. memset(rgbZeroSig, 0, sizeof(rgbZeroSig));
  5132. // set up the pointers
  5133. pbPostCRC = pbStart + *pdwCRCOffset + sizeof(DWORD);
  5134. if (pbRsrcSig > pbRsrcMAC) // MAC is first Rsrc
  5135. {
  5136. cbCRCToRsrc1 = (DWORD)(pbRsrcMAC - pbPostCRC);
  5137. pbRsrc1ToRsrc2 = pbRsrcMAC + cbRsrcMAC;
  5138. cbRsrc1ToRsrc2 = (DWORD)(pbRsrcSig - pbRsrc1ToRsrc2);
  5139. pbPostRsrc = pbRsrcSig + cbRsrcSig;
  5140. cbPostRsrc = (cbImage - (DWORD)(pbPostRsrc - pbStart));
  5141. // zero pointers
  5142. pbZeroRsrc1 = rgbZeroMAC;
  5143. cbZeroRsrc1 = cbRsrcMAC;
  5144. pbZeroRsrc2 = rgbZeroSig;
  5145. cbZeroRsrc2 = cbRsrcSig;
  5146. }
  5147. else // Sig is first Rsrc
  5148. {
  5149. cbCRCToRsrc1 = (DWORD)(pbRsrcSig - pbPostCRC);
  5150. pbRsrc1ToRsrc2 = pbRsrcSig + cbRsrcSig;
  5151. cbRsrc1ToRsrc2 = (DWORD)(pbRsrcMAC - pbRsrc1ToRsrc2);
  5152. pbPostRsrc = pbRsrcMAC + cbRsrcMAC;
  5153. cbPostRsrc = (cbImage - (DWORD)(pbPostRsrc - pbStart));
  5154. // zero pointers
  5155. pbZeroRsrc1 = rgbZeroSig;
  5156. cbZeroRsrc1 = cbRsrcSig;
  5157. pbZeroRsrc2 = rgbZeroMAC;
  5158. cbZeroRsrc2 = cbRsrcMAC;
  5159. }
  5160. // init the key table
  5161. deskey(&DESKeyTable, (LPBYTE)rgbMACDESKey);
  5162. // MAC up to the CRC
  5163. dwSts = MACBytesOfFile((HANDLE)IntToPtr(hFile), dwCRCOffset, &DESKeyTable,
  5164. rgbTmp, &cbTmp, rgbMAC);
  5165. if (ERROR_SUCCESS != dwSts)
  5166. {
  5167. dwReturn = dwSts;
  5168. goto ErrorExit;
  5169. }
  5170. // pretend CRC is zeroed
  5171. MACBytes(&DESKeyTable, (BYTE*)&dwZeroCRC, sizeof(DWORD), rgbTmp, &cbTmp,
  5172. rgbMAC);
  5173. if (!SetFilePointer((HANDLE)IntToPtr(hFile), sizeof(DWORD), NULL, FILE_CURRENT))
  5174. {
  5175. dwReturn = GetLastError();
  5176. goto ErrorExit;
  5177. }
  5178. // MAC from CRC to first resource
  5179. dwSts = MACBytesOfFile((HANDLE)IntToPtr(hFile), cbCRCToRsrc1, &DESKeyTable,
  5180. rgbTmp, &cbTmp, rgbMAC);
  5181. if (ERROR_SUCCESS != dwSts)
  5182. {
  5183. dwReturn = dwSts;
  5184. goto ErrorExit;
  5185. }
  5186. // pretend image has zeroed first resource
  5187. MACBytes(&DESKeyTable, (BYTE*)pbZeroRsrc1, cbZeroRsrc1, rgbTmp, &cbTmp,
  5188. rgbMAC);
  5189. if (!SetFilePointer((HANDLE)IntToPtr(hFile), cbZeroRsrc1, NULL, FILE_CURRENT))
  5190. {
  5191. dwReturn = GetLastError();
  5192. goto ErrorExit;
  5193. }
  5194. // MAC from first resource to second
  5195. dwSts = MACBytesOfFile((HANDLE)IntToPtr(hFile), cbRsrc1ToRsrc2,
  5196. &DESKeyTable, rgbTmp, &cbTmp, rgbMAC);
  5197. if (ERROR_SUCCESS != dwSts)
  5198. {
  5199. dwReturn = dwSts;
  5200. goto ErrorExit;
  5201. }
  5202. // pretend image has zeroed second Resource
  5203. MACBytes(&DESKeyTable, (BYTE*)pbZeroRsrc2, cbZeroRsrc2, rgbTmp, &cbTmp,
  5204. rgbMAC);
  5205. if (!SetFilePointer((HANDLE)IntToPtr(hFile), cbZeroRsrc2, NULL, FILE_CURRENT))
  5206. {
  5207. dwReturn = GetLastError();
  5208. goto ErrorExit;
  5209. }
  5210. // MAC after the resource
  5211. dwSts = MACBytesOfFile((HANDLE)IntToPtr(hFile), cbPostRsrc, &DESKeyTable,
  5212. rgbTmp, &cbTmp, rgbMAC);
  5213. if (ERROR_SUCCESS != dwSts)
  5214. {
  5215. dwReturn = dwSts;
  5216. goto ErrorExit;
  5217. }
  5218. if (0 != memcmp(rgbMAC, pbRsrcMAC + sizeof(DWORD) * 2, DES_BLOCKLEN))
  5219. {
  5220. dwReturn = (DWORD)NTE_FAIL;
  5221. goto ErrorExit;
  5222. }
  5223. dwReturn = ERROR_SUCCESS;
  5224. ErrorExit:
  5225. if (NULL != pbStart)
  5226. UnmapViewOfFile(pbStart);
  5227. if (NULL != hMapping)
  5228. CloseHandle(hMapping);
  5229. if (HFILE_ERROR != hFile)
  5230. _lclose(hFile);
  5231. return dwReturn;
  5232. }
  5233. // **********************************************************************
  5234. // SelfMACCheck performs a DES MAC on the binary image of this DLL
  5235. // **********************************************************************
  5236. DWORD
  5237. SelfMACCheck(
  5238. IN LPSTR pszImage)
  5239. {
  5240. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  5241. HFILE hFileProv = HFILE_ERROR;
  5242. DWORD cbImage;
  5243. OFSTRUCT ImageInfoBuf;
  5244. DWORD dwSts;
  5245. #ifdef _DEBUG
  5246. return ERROR_SUCCESS;
  5247. #endif
  5248. // Check file size
  5249. hFileProv = OpenFile(pszImage, &ImageInfoBuf, OF_READ);
  5250. if (HFILE_ERROR == hFileProv)
  5251. {
  5252. dwSts = GetLastError();
  5253. if (ERROR_FILE_NOT_FOUND == dwSts)
  5254. dwReturn = (DWORD)NTE_PROV_DLL_NOT_FOUND;
  5255. else
  5256. dwReturn = dwSts;
  5257. goto ErrorExit;
  5258. }
  5259. cbImage = GetFileSize((HANDLE)IntToPtr(hFileProv), NULL);
  5260. if ((DWORD)(-1) == cbImage)
  5261. {
  5262. dwReturn = GetLastError();
  5263. goto ErrorExit;
  5264. }
  5265. _lclose(hFileProv);
  5266. hFileProv = HFILE_ERROR;
  5267. dwSts = MACTheFile(pszImage, cbImage);
  5268. if (ERROR_SUCCESS != dwSts)
  5269. {
  5270. dwReturn = dwSts;
  5271. goto ErrorExit;
  5272. }
  5273. dwReturn = ERROR_SUCCESS;
  5274. ErrorExit:
  5275. if (HFILE_ERROR != hFileProv)
  5276. _lclose(hFileProv);
  5277. return dwReturn;
  5278. }