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.

762 lines
24 KiB

  1. /*****************************************************************************\
  2. FILE: passwordapi.cpp
  3. DESCRIPTION:
  4. We want to store FTP passwords in a secure API. We will use the
  5. PStore APIs on WinNT and the PWL APIs on Win9x. This code was taken
  6. from wininet.
  7. BryanSt (Bryan Starbuck) - Created
  8. BryanSt (Bryan Starbuck) - Updated to support DP API for Win2k
  9. Copyright (c) 1998-2000 Microsoft Corporation
  10. \*****************************************************************************/
  11. #include "priv.h"
  12. #include <pstore.h>
  13. #include <wincrypt.h> // Defines DATA_BLOB
  14. #include <passwordapi.h>
  15. typedef HRESULT (*PFNPSTORECREATEINSTANCE)(IPStore**, PST_PROVIDERID*, VOID*, DWORD);
  16. // Globals
  17. #define SIZE_MAX_KEY_SIZE 2048 // For lookup key (In our case, URL w/user name & server, without password & path)
  18. #define SIZE_MAX_VALUE_SIZE 2048 // For stored value (In our case the password)
  19. // MPR.DLL exports used by top level API.
  20. typedef DWORD (APIENTRY *PFWNETGETCACHEDPASSWORD) (LPCSTR, WORD, LPCSTR, LPWORD, BYTE);
  21. typedef DWORD (APIENTRY *PFWNETCACHEPASSWORD) (LPCSTR, WORD, LPCSTR, WORD, BYTE, UINT);
  22. typedef DWORD (APIENTRY *PFWNETREMOVECACHEDPASSWORD) (LPCSTR, WORD, BYTE);
  23. // PWL related variables.
  24. static HMODULE MhmodWNET = NULL;
  25. static PFWNETGETCACHEDPASSWORD g_pfWNetGetCachedPassword = NULL;
  26. static PFWNETCACHEPASSWORD g_pfWNetCachePassword = NULL;
  27. static PFWNETREMOVECACHEDPASSWORD g_pfWNetRemoveCachedPassword = NULL;
  28. // Pstore related variables.
  29. static PFNPSTORECREATEINSTANCE s_pPStoreCreateInstance = NULL;
  30. #define STR_FTP_CACHE_CREDENTIALS L"MS IE FTP Passwords";
  31. #define PSTORE_MODULE TEXT("pstorec.dll")
  32. #define WNETDLL_MODULE TEXT("mpr.dll")
  33. #define WNETGETCACHEDPASS "WNetGetCachedPassword"
  34. #define WNETCACHEPASS "WNetCachePassword"
  35. #define WNETREMOVECACHEDPASS "WNetRemoveCachedPassword"
  36. #define DISABLE_PASSWORD_CACHE 1
  37. // PWL related defines.
  38. // Password-cache-entry, this should be in PCACHE.
  39. #define PCE_WWW_BASIC 0x13
  40. // NOTE: We would logically like to unload the dll of the API we use (s_pPStoreCreateInstance) via FreeLibrary(PSTORE_MODULE),
  41. // but we would need to do that when we unload our DLL. We can't do that because it leads to crashing
  42. // and badness.
  43. // Wininet uses this GUID for pstore:
  44. // {5E7E8100-9138-11d1-945A-00C04FC308FF}
  45. static const GUID GUID_PStoreType =
  46. { 0x5e7e8100, 0x9138, 0x11d1, { 0x94, 0x5a, 0x0, 0xc0, 0x4f, 0xc3, 0x8, 0xff } };
  47. // Private function prototypes.
  48. // PWL private function prototypes.
  49. DWORD PWLSetCachedCredentials(LPCSTR pszKey, DWORD cbKey, LPCSTR pszCred, DWORD cbCred);
  50. DWORD PWLGetCachedCredentials(LPCSTR pszKey, DWORD cbKey, LPSTR cbCred, LPDWORD pcbCred);
  51. DWORD PWLRemoveCachedCredentials(LPCSTR pszKey, DWORD cbKey);
  52. BOOL LoadWNet(VOID);
  53. // PStore private function prototypes.
  54. DWORD PStoreSetCachedCredentials(LPCWSTR pszKey, LPCWSTR pszCred, DWORD cbCred, BOOL fRemove=FALSE);
  55. DWORD PStoreGetCachedCredentials(LPCWSTR pszKey, LPWSTR pszCred, LPDWORD pcbCred);
  56. DWORD PStoreRemoveCachedCredentials(LPCWSTR pszKey);
  57. HRESULT CreatePStore(IPStore **ppIPStore);
  58. STDAPI ReleasePStore(IPStore *pIPStore);
  59. #define FEATURE_USE_DPAPI
  60. // The DPAPI is an improved version of PStore that started shipping in Win2k. This
  61. // has better security and should be used when it is available. Pete Skelly informed
  62. // me of this. CliffV also has a password credentials manager, but that probably wouldn't
  63. // be applicable for FTP.
  64. HRESULT DPAPISetCachedCredentials(IN LPCWSTR pszKey, IN LPCWSTR pszValue, IN OPTIONAL LPCWSTR pszDescription);
  65. HRESULT DPAPIGetCachedCredentials(IN LPCWSTR pszKey, IN LPWSTR pszValue, IN int cchSize);
  66. HRESULT DPAPIRemoveCachedCredentials(IN LPCWSTR pszKey);
  67. // *--------------------------- Top Level APIs ---------------------------------*
  68. /****************************************************\
  69. FUNCTION: InitCredentialPersist
  70. DESCRIPTION:
  71. Try to init the cache.
  72. PARAMETERS:
  73. Return Value:
  74. S_OK if it will work correctly.
  75. S_FASE if turned off by admin.
  76. HRESULT_FROM_WIN32(ERROR_PRODUCT_UNINSTALLED) if the password caching APIs aren't installed on NT.
  77. \****************************************************/
  78. HRESULT InitCredentialPersist(void)
  79. {
  80. HRESULT hr = S_OK;
  81. DWORD dwDisable;
  82. DWORD cbSize = sizeof(dwDisable);
  83. // First check to see if persistence is disabled via registry.
  84. if ((ERROR_SUCCESS == SHGetValue(HKEY_CURRENT_USER, SZ_REGKEY_INTERNET_SETTINGS, SZ_REGVALUE_DISABLE_PASSWORD_CACHE, NULL, (void *)&dwDisable, &cbSize))
  85. && (dwDisable == DISABLE_PASSWORD_CACHE))
  86. {
  87. // Persistence disabled via registry.
  88. hr = S_FALSE;
  89. }
  90. if (S_OK == hr)
  91. {
  92. // We use PWL for Win95; this should be available.
  93. if (!IsOS(OS_NT))
  94. {
  95. // hr already equals S_OK and no more work is needed.
  96. }
  97. else
  98. {
  99. HINSTANCE hInstPStoreC = 0;
  100. // If is WinNT, check if PStore is installed.
  101. hInstPStoreC = LoadLibrary(PSTORE_MODULE);
  102. if (!hInstPStoreC)
  103. hr = HRESULT_FROM_WIN32(ERROR_PRODUCT_UNINSTALLED);
  104. else
  105. {
  106. // Get CreatePStoreInstance function pointer.
  107. s_pPStoreCreateInstance = (PFNPSTORECREATEINSTANCE) GetProcAddress(hInstPStoreC, "PStoreCreateInstance");
  108. if (!s_pPStoreCreateInstance)
  109. hr = HRESULT_FROM_WIN32(ERROR_PRODUCT_UNINSTALLED);
  110. else
  111. {
  112. IPStore * pIPStore = NULL;
  113. // Create an IPStore.
  114. hr = CreatePStore(&pIPStore);
  115. // We just did this to see if it worked, so
  116. // the hr was set correctly.
  117. if (pIPStore)
  118. ReleasePStore(pIPStore);
  119. }
  120. }
  121. }
  122. }
  123. return hr;
  124. }
  125. /****************************************************\
  126. FUNCTION: SetCachedCredentials
  127. DESCRIPTION:
  128. PARAMETERS:
  129. \****************************************************/
  130. HRESULT SetCachedCredentials(LPCWSTR pwzKey, LPCWSTR pwzValue)
  131. {
  132. // Check if credential persistence is available.
  133. HRESULT hr = InitCredentialPersist();
  134. if (S_OK == hr)
  135. {
  136. // Store credentials.
  137. if (!IsOS(OS_NT))
  138. {
  139. // Use the PWL (Password List) API on Win9x
  140. CHAR szKey[SIZE_MAX_KEY_SIZE];
  141. CHAR szValue[SIZE_MAX_VALUE_SIZE];
  142. ASSERT(lstrlenW(pwzKey) < ARRAYSIZE(szKey));
  143. ASSERT(lstrlenW(pwzValue) < ARRAYSIZE(szValue));
  144. SHUnicodeToAnsi(pwzKey, szKey, ARRAYSIZE(szKey));
  145. SHUnicodeToAnsi(pwzValue, szValue, ARRAYSIZE(szValue));
  146. DWORD cbKey = ((lstrlenA(szKey) + 1) * sizeof(szKey[0]));
  147. DWORD cbCred = ((lstrlenA(szValue) + 1) * sizeof(szValue[0]));
  148. // Store credentials using PWL.
  149. DWORD dwError = PWLSetCachedCredentials(szKey, cbKey, szValue, cbCred);
  150. hr = HRESULT_FROM_WIN32(dwError);
  151. }
  152. else
  153. {
  154. hr = E_FAIL;
  155. #ifdef FEATURE_USE_DPAPI
  156. if (5 <= GetOSVer())
  157. {
  158. // Use the DPAPI (Data Protection) API on Win2k and later.
  159. // This has the latest and greatest in protection.
  160. WCHAR wzDescription[MAX_URL_STRING];
  161. wnsprintfW(wzDescription, ARRAYSIZE(wzDescription), L"FTP password for: %ls", pwzKey);
  162. hr = DPAPISetCachedCredentials(pwzKey, pwzValue, wzDescription);
  163. }
  164. #endif // FEATURE_USE_DPAPI
  165. if (FAILED(hr)) // Fall back to PStore in case DP is won't work unless we do UI.
  166. {
  167. // Use the PStore API on pre-Win2k.
  168. DWORD cbCred = ((lstrlenW(pwzValue) + 1) * sizeof(pwzValue[0]));
  169. // Store credentials using PStore.
  170. DWORD dwError = PStoreSetCachedCredentials(pwzKey, pwzValue, cbCred);
  171. hr = HRESULT_FROM_WIN32(dwError);
  172. }
  173. }
  174. }
  175. return hr;
  176. }
  177. /****************************************************\
  178. FUNCTION: GetCachedCredentials
  179. DESCRIPTION:
  180. PARAMETERS:
  181. \****************************************************/
  182. HRESULT GetCachedCredentials(LPCWSTR pwzKey, LPWSTR pwzValue, DWORD cchSize)
  183. {
  184. // Check if credential persistence is available.
  185. HRESULT hr = InitCredentialPersist();
  186. if (S_OK == hr)
  187. {
  188. // Store credentials.
  189. if (!IsOS(OS_NT))
  190. {
  191. // Use the PWL (Password List) API on Win9x
  192. CHAR szKey[SIZE_MAX_KEY_SIZE];
  193. CHAR szValue[SIZE_MAX_VALUE_SIZE];
  194. DWORD cchTempSize = ARRAYSIZE(szValue);
  195. ASSERT(lstrlenW(pwzKey) < ARRAYSIZE(szKey));
  196. ASSERT(cchSize < ARRAYSIZE(szValue));
  197. SHUnicodeToAnsi(pwzKey, szKey, ARRAYSIZE(szKey));
  198. DWORD cbKey = ((lstrlenA(szKey) + 1) * sizeof(szKey[0]));
  199. szValue[0] = 0;
  200. // Store credentials using PWL.
  201. DWORD dwError = PWLGetCachedCredentials(szKey, cbKey, szValue, &cchTempSize);
  202. hr = HRESULT_FROM_WIN32(dwError);
  203. SHAnsiToUnicode(szValue, pwzValue, cchSize);
  204. }
  205. else
  206. {
  207. hr = E_FAIL;
  208. #ifdef FEATURE_USE_DPAPI
  209. if (5 <= GetOSVer())
  210. {
  211. // Use the DPAPI (Data Protection) API on Win2k and later.
  212. // This has the latest and greatest in protection.
  213. hr = DPAPIGetCachedCredentials(pwzKey, pwzValue, cchSize);
  214. }
  215. #endif // FEATURE_USE_DPAPI
  216. if (FAILED(hr)) // Fall back to PStore in case DP is won't work unless we do UI.
  217. {
  218. // Use the PStore API on pre-Win2k.
  219. cchSize++; // Include terminator.
  220. cchSize *= sizeof(pwzValue[0]);
  221. pwzValue[0] = 0;
  222. // Store credentials using PStore.
  223. DWORD dwError = PStoreGetCachedCredentials(pwzKey, pwzValue, &cchSize);
  224. hr = HRESULT_FROM_WIN32(dwError);
  225. }
  226. }
  227. }
  228. return hr;
  229. }
  230. /****************************************************\
  231. FUNCTION: RemoveCachedCredentials
  232. DESCRIPTION:
  233. PARAMETERS:
  234. \****************************************************/
  235. HRESULT RemoveCachedCredentials(LPCWSTR pwzKey)
  236. {
  237. // Check if credential persistence is available.
  238. HRESULT hr = InitCredentialPersist();
  239. if (S_OK == hr)
  240. {
  241. // Store credentials.
  242. if (!IsOS(OS_NT))
  243. {
  244. // Use the PWL (Password List) API on Win9x
  245. CHAR szKey[SIZE_MAX_KEY_SIZE];
  246. ASSERT(lstrlenW(pwzKey) < ARRAYSIZE(szKey));
  247. SHUnicodeToAnsi(pwzKey, szKey, ARRAYSIZE(szKey));
  248. DWORD cbKey = (lstrlenA(szKey) * sizeof(szKey[0]));
  249. // Remove credentials from PWL.
  250. DWORD dwError = PWLRemoveCachedCredentials(szKey, cbKey);
  251. hr = HRESULT_FROM_WIN32(dwError);
  252. }
  253. else
  254. {
  255. hr = E_FAIL;
  256. #ifdef FEATURE_USE_DPAPI
  257. if (5 <= GetOSVer())
  258. {
  259. // Use the DPAPI (Data Protection) API on Win2k and later.
  260. // This has the latest and greatest in protection.
  261. hr = DPAPIRemoveCachedCredentials(pwzKey);
  262. }
  263. #endif // FEATURE_USE_DPAPI
  264. if (FAILED(hr)) // Fall back to PStore in case DP is won't work unless we do UI.
  265. {
  266. // Remove credentials from PStore.
  267. DWORD dwError = PStoreRemoveCachedCredentials(pwzKey);
  268. hr = HRESULT_FROM_WIN32(dwError);
  269. }
  270. }
  271. }
  272. return hr;
  273. }
  274. /*--------------------------- PWL Functions ---------------------------------*/
  275. /*-----------------------------------------------------------------------------
  276. PWLSetCachedCredentials
  277. ---------------------------------------------------------------------------*/
  278. DWORD PWLSetCachedCredentials(LPCSTR pszKey, DWORD cbKey,
  279. LPCSTR pszCred, DWORD cbCred)
  280. {
  281. DWORD dwError;
  282. // Load WNet.
  283. if (!LoadWNet())
  284. return ERROR_INTERNET_INTERNAL_ERROR;
  285. // Store credentials.
  286. dwError = (*g_pfWNetCachePassword) (pszKey, (WORD) cbKey, pszCred, (WORD) cbCred, PCE_WWW_BASIC, 0);
  287. return dwError;
  288. }
  289. /*-----------------------------------------------------------------------------
  290. PWLGetCachedCredentials
  291. ---------------------------------------------------------------------------*/
  292. DWORD PWLGetCachedCredentials (LPCSTR pszKey, DWORD cbKey,
  293. LPSTR pszCred, LPDWORD pcbCred)
  294. {
  295. DWORD dwError;
  296. // Load WNet.
  297. if (!LoadWNet())
  298. return ERROR_INTERNET_INTERNAL_ERROR;
  299. // Retrieve credentials.
  300. dwError = (*g_pfWNetGetCachedPassword) (pszKey, (WORD) cbKey, pszCred,
  301. (LPWORD) pcbCred, PCE_WWW_BASIC);
  302. return dwError;
  303. }
  304. /*-----------------------------------------------------------------------------
  305. PWLRemoveCachedCredentials
  306. ---------------------------------------------------------------------------*/
  307. DWORD PWLRemoveCachedCredentials (LPCSTR pszKey, DWORD cbKey)
  308. {
  309. DWORD dwError;
  310. // Load WNet.
  311. if (!LoadWNet())
  312. return ERROR_INTERNET_INTERNAL_ERROR;
  313. dwError = (*g_pfWNetRemoveCachedPassword) (pszKey, (WORD) cbKey, PCE_WWW_BASIC);
  314. return dwError;
  315. }
  316. // PWL utility functions.
  317. /*-----------------------------------------------------------------------------
  318. LoadWNet
  319. ---------------------------------------------------------------------------*/
  320. BOOL LoadWNet(VOID)
  321. {
  322. BOOL fReturn;
  323. // MPR.DLL already loaded.
  324. if (MhmodWNET)
  325. {
  326. fReturn = TRUE;
  327. goto quit;
  328. }
  329. // Load MPR.DLL
  330. MhmodWNET = LoadLibrary(WNETDLL_MODULE);
  331. // Fail if not loaded.
  332. if (MhmodWNET)
  333. {
  334. fReturn = TRUE;
  335. }
  336. else
  337. {
  338. fReturn = FALSE;
  339. goto quit;
  340. }
  341. g_pfWNetGetCachedPassword = (PFWNETGETCACHEDPASSWORD) GetProcAddress(MhmodWNET, WNETGETCACHEDPASS);
  342. g_pfWNetCachePassword = (PFWNETCACHEPASSWORD) GetProcAddress(MhmodWNET, WNETCACHEPASS);
  343. g_pfWNetRemoveCachedPassword = (PFWNETREMOVECACHEDPASSWORD) GetProcAddress(MhmodWNET, WNETREMOVECACHEDPASS);
  344. // Ensure we have all function pointers.
  345. if (!(g_pfWNetGetCachedPassword
  346. && g_pfWNetCachePassword
  347. && g_pfWNetRemoveCachedPassword))
  348. {
  349. fReturn = FALSE;
  350. }
  351. quit:
  352. return fReturn;
  353. }
  354. /*------------------------- PStore Functions -------------------------------*/
  355. /*-----------------------------------------------------------------------------
  356. PStoreSetCachedCredentials
  357. ---------------------------------------------------------------------------*/
  358. DWORD PStoreSetCachedCredentials(LPCWSTR pszKey, LPCWSTR pszCred, DWORD cbCred, BOOL fRemove)
  359. {
  360. ASSERT(s_pPStoreCreateInstance);
  361. HRESULT hr;
  362. DWORD dwError;
  363. PST_TYPEINFO typeInfo;
  364. PST_PROMPTINFO promptInfo = {0};
  365. GUID itemType = GUID_PStoreType;
  366. GUID itemSubtype = GUID_NULL;
  367. IPStore * pStore = NULL;
  368. // PST_TYPEINFO data.
  369. typeInfo.cbSize = sizeof(typeInfo);
  370. typeInfo.szDisplayName = STR_FTP_CACHE_CREDENTIALS;
  371. // PST_PROMPTINFO data (no prompting desired).
  372. promptInfo.cbSize = sizeof(promptInfo);
  373. promptInfo.dwPromptFlags = 0;
  374. promptInfo.hwndApp = NULL;
  375. promptInfo.szPrompt = NULL;
  376. // Create a PStore interface.
  377. hr = CreatePStore(&pStore);
  378. if (!SUCCEEDED(hr))
  379. goto quit;
  380. ASSERT(pStore != NULL);
  381. // Create a type in HKCU.
  382. hr = pStore->CreateType(PST_KEY_CURRENT_USER, &itemType, &typeInfo, 0);
  383. if (!((SUCCEEDED(hr)) || (hr == PST_E_TYPE_EXISTS)))
  384. goto quit;
  385. // Create subtype.
  386. hr = pStore->CreateSubtype(PST_KEY_CURRENT_USER, &itemType,
  387. &itemSubtype, &typeInfo, NULL, 0);
  388. if (!((SUCCEEDED(hr)) || (hr == PST_E_TYPE_EXISTS)))
  389. goto quit;
  390. // Valid credentials are written; No credentials imples
  391. // that the key and credentials are to be deleted.
  392. if (pszCred && cbCred && !fRemove)
  393. {
  394. // Write key and credentials to PStore.
  395. hr = pStore->WriteItem(PST_KEY_CURRENT_USER,
  396. &itemType,
  397. &itemSubtype,
  398. pszKey,
  399. cbCred,
  400. (LPBYTE) pszCred,
  401. &promptInfo,
  402. PST_CF_NONE,
  403. 0);
  404. }
  405. else
  406. {
  407. // Delete key and credentials from PStore.
  408. hr = pStore->DeleteItem(PST_KEY_CURRENT_USER,
  409. &itemType,
  410. &itemSubtype,
  411. pszKey,
  412. &promptInfo,
  413. 0);
  414. }
  415. quit:
  416. // Release the interface, convert error and return.
  417. ReleasePStore(pStore);
  418. if (SUCCEEDED(hr))
  419. dwError = ERROR_SUCCESS;
  420. else
  421. dwError = ERROR_INTERNET_INTERNAL_ERROR;
  422. return dwError;
  423. }
  424. /*-----------------------------------------------------------------------------
  425. PStoreGetCachedCredentials
  426. ---------------------------------------------------------------------------*/
  427. DWORD PStoreGetCachedCredentials(LPCWSTR pszKey, LPWSTR pszCred, LPDWORD pcbCred)
  428. {
  429. ASSERT(s_pPStoreCreateInstance);
  430. HRESULT hr ;
  431. DWORD dwError;
  432. LPBYTE pbData;
  433. PST_PROMPTINFO promptInfo = {0};
  434. GUID itemType = GUID_PStoreType;
  435. GUID itemSubtype = GUID_NULL;
  436. IPStore* pStore = NULL;
  437. // PST_PROMPTINFO data (no prompting desired).
  438. promptInfo.cbSize = sizeof(promptInfo);
  439. promptInfo.dwPromptFlags = 0;
  440. promptInfo.hwndApp = NULL;
  441. promptInfo.szPrompt = NULL;
  442. // Create a PStore interface.
  443. hr = CreatePStore(&pStore);
  444. if (!SUCCEEDED(hr))
  445. goto quit;
  446. ASSERT(pStore != NULL);
  447. // Read the credentials from PStore.
  448. hr = pStore->ReadItem(PST_KEY_CURRENT_USER,
  449. &itemType,
  450. &itemSubtype,
  451. pszKey,
  452. pcbCred,
  453. (LPBYTE*) &pbData,
  454. &promptInfo,
  455. 0);
  456. // Copy credentials and free buffer allocated by ReadItem.
  457. if (SUCCEEDED(hr))
  458. {
  459. memcpy(pszCred, pbData, *pcbCred);
  460. CoTaskMemFree(pbData);
  461. //hr = S_OK;
  462. }
  463. quit:
  464. // Release the interface, convert error and return.
  465. ReleasePStore(pStore);
  466. if (SUCCEEDED(hr))
  467. dwError = ERROR_SUCCESS;
  468. else
  469. dwError = ERROR_INTERNET_INTERNAL_ERROR;
  470. return dwError;
  471. }
  472. /*-----------------------------------------------------------------------------
  473. PStoreRemoveCachedCredentials
  474. ---------------------------------------------------------------------------*/
  475. DWORD PStoreRemoveCachedCredentials(LPCWSTR pszKey)
  476. {
  477. // Pass in TRUE to remove credentials.
  478. return PStoreSetCachedCredentials(pszKey, NULL, 0, TRUE);
  479. }
  480. // PStore utility functions
  481. /*-----------------------------------------------------------------------------
  482. CreatePStore
  483. ---------------------------------------------------------------------------*/
  484. HRESULT CreatePStore(IPStore **ppIPStore)
  485. {
  486. return s_pPStoreCreateInstance (ppIPStore, NULL, NULL, 0);
  487. }
  488. /*-----------------------------------------------------------------------------
  489. ReleasePStore
  490. ---------------------------------------------------------------------------*/
  491. STDAPI ReleasePStore(IPStore *pIPStore)
  492. {
  493. HRESULT hr;
  494. if (pIPStore)
  495. {
  496. pIPStore->Release();
  497. hr = S_OK;
  498. }
  499. else
  500. {
  501. hr = E_POINTER;
  502. }
  503. return hr;
  504. }
  505. /*--------------------------- DP (Data Protection) Functions ---------------------------------*/
  506. void ClearDataBlob(DATA_BLOB * pdbBlobToFree)
  507. {
  508. if (pdbBlobToFree && pdbBlobToFree->pbData)
  509. {
  510. LocalFree(pdbBlobToFree->pbData);
  511. }
  512. }
  513. /*-----------------------------------------------------------------------------
  514. PWLSetCachedCredentials
  515. ---------------------------------------------------------------------------*/
  516. HRESULT DPAPISetCachedCredentials(IN LPCWSTR pszKey, IN LPCWSTR pszValue, IN OPTIONAL LPCWSTR pszDescription)
  517. {
  518. HRESULT hr = S_OK;
  519. DATA_BLOB dbEncrypted = {0};
  520. DATA_BLOB dbUnencrypted;
  521. dbUnencrypted.pbData = (unsigned char *) pszValue;
  522. dbUnencrypted.cbData = ((lstrlenW(pszValue) + 1) * sizeof(pszValue[0]));
  523. if (!_CryptProtectData(&dbUnencrypted, pszDescription, NULL, NULL, NULL, CRYPTPROTECT_UI_FORBIDDEN, &dbEncrypted))
  524. {
  525. hr = HRESULT_FROM_WIN32(GetLastError()); // It failed, so get the real err value.
  526. }
  527. else
  528. {
  529. WCHAR wzDPKey[MAX_URL_STRING+MAX_PATH];
  530. wnsprintfW(wzDPKey, ARRAYSIZE(wzDPKey), L"DPAPI: %ls", pszKey);
  531. AssertMsg((NULL != dbEncrypted.pbData), TEXT("If the API succeeded but they didn't give us the encrypted version. -BryanSt"));
  532. // Use the PStore to actually store the data, but we use a different key.
  533. DWORD dwError = PStoreSetCachedCredentials(wzDPKey, (LPCWSTR)dbEncrypted.pbData, dbEncrypted.cbData);
  534. hr = HRESULT_FROM_WIN32(dwError);
  535. }
  536. ClearDataBlob(&dbEncrypted);
  537. return hr;
  538. }
  539. #define MAX_ENCRYPTED_PASSWORD_SIZE 20*1024 // The DP API should be able to store our tiny encrypted password into 20k.
  540. /*-----------------------------------------------------------------------------
  541. PWLGetCachedCredentials
  542. ---------------------------------------------------------------------------*/
  543. HRESULT DPAPIGetCachedCredentials(IN LPCWSTR pszKey, IN LPWSTR pszValue, IN int cchSize)
  544. {
  545. HRESULT hr = E_OUTOFMEMORY;
  546. DATA_BLOB dbEncrypted = {0};
  547. dbEncrypted.pbData = (unsigned char *) LocalAlloc(LPTR, MAX_ENCRYPTED_PASSWORD_SIZE);
  548. dbEncrypted.cbData = MAX_ENCRYPTED_PASSWORD_SIZE;
  549. StrCpyNW(pszValue, L"", cchSize); // Init the buffer in case of an error.
  550. if (dbEncrypted.pbData)
  551. {
  552. WCHAR wzDPKey[MAX_URL_STRING+MAX_PATH];
  553. // Use the PStore to actually store the data, but we use a different key.
  554. wnsprintfW(wzDPKey, ARRAYSIZE(wzDPKey), L"DPAPI: %ls", pszKey);
  555. DWORD dwError = PStoreGetCachedCredentials(wzDPKey, (LPWSTR)dbEncrypted.pbData, &dbEncrypted.cbData);
  556. hr = HRESULT_FROM_WIN32(dwError);
  557. if (SUCCEEDED(hr))
  558. {
  559. DATA_BLOB dbUnencrypted = {0};
  560. if (_CryptUnprotectData(&dbEncrypted, NULL, NULL, NULL, NULL, CRYPTPROTECT_UI_FORBIDDEN, &dbUnencrypted))
  561. {
  562. StrCpyNW(pszValue, (LPCWSTR)dbUnencrypted.pbData, cchSize); // Init the buffer in case of an error.
  563. ClearDataBlob(&dbUnencrypted);
  564. }
  565. else
  566. {
  567. hr = HRESULT_FROM_WIN32(GetLastError()); // It failed, so get the real err value.
  568. }
  569. }
  570. LocalFree(dbEncrypted.pbData);
  571. }
  572. return hr;
  573. }
  574. /*-----------------------------------------------------------------------------
  575. PWLRemoveCachedCredentials
  576. ---------------------------------------------------------------------------*/
  577. HRESULT DPAPIRemoveCachedCredentials(IN LPCWSTR pszKey)
  578. {
  579. WCHAR wzDPKey[MAX_URL_STRING+MAX_PATH];
  580. wnsprintfW(wzDPKey, ARRAYSIZE(wzDPKey), L"DPAPI: %ls", pszKey);
  581. DWORD dwError = PStoreRemoveCachedCredentials(wzDPKey);
  582. return HRESULT_FROM_WIN32(dwError);
  583. }