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

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