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.

1025 lines
28 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: pwutil.cpp
  4. //
  5. // Module: Common Source
  6. //
  7. // Synopsis: Simple encryption funcs - borrowed from RAS
  8. //
  9. // Copyright (c) 1994-1999 Microsoft Corporation
  10. //
  11. // Author: nickball Created 08/03/99
  12. //
  13. //+----------------------------------------------------------------------------
  14. #define PASSWORDMAGIC 0xA5
  15. VOID
  16. ReverseSzA(
  17. CHAR* psz )
  18. /* Reverses order of characters in 'psz'.
  19. */
  20. {
  21. CHAR* pszBegin;
  22. CHAR* pszEnd;
  23. for (pszBegin = psz, pszEnd = psz + lstrlenA( psz ) - 1;
  24. pszBegin < pszEnd;
  25. ++pszBegin, --pszEnd)
  26. {
  27. CHAR ch = *pszBegin;
  28. *pszBegin = *pszEnd;
  29. *pszEnd = ch;
  30. }
  31. }
  32. VOID
  33. ReverseSzW(
  34. WCHAR* psz )
  35. /* Reverses order of characters in 'psz'.
  36. */
  37. {
  38. WCHAR* pszBegin;
  39. WCHAR* pszEnd;
  40. for (pszBegin = psz, pszEnd = psz + lstrlenW( psz ) - 1;
  41. pszBegin < pszEnd;
  42. ++pszBegin, --pszEnd)
  43. {
  44. WCHAR ch = *pszBegin;
  45. *pszBegin = *pszEnd;
  46. *pszEnd = ch;
  47. }
  48. }
  49. VOID
  50. CmDecodePasswordA(
  51. IN OUT CHAR* pszPassword )
  52. /* Un-obfuscate 'pszPassword' in place.
  53. **
  54. ** Returns Nothing
  55. */
  56. {
  57. CmEncodePasswordA( pszPassword );
  58. }
  59. VOID
  60. CmDecodePasswordW(
  61. IN OUT WCHAR* pszPassword )
  62. /* Un-obfuscate 'pszPassword' in place.
  63. **
  64. ** Returns the address of 'pszPassword'.
  65. */
  66. {
  67. CmEncodePasswordW( pszPassword );
  68. }
  69. VOID
  70. CmEncodePasswordA(
  71. IN OUT CHAR* pszPassword )
  72. /* Obfuscate 'pszPassword' in place to foil memory scans for passwords.
  73. **
  74. ** Returns Nothing
  75. */
  76. {
  77. if (pszPassword)
  78. {
  79. CHAR* psz;
  80. ReverseSzA( pszPassword );
  81. for (psz = pszPassword; *psz != '\0'; ++psz)
  82. {
  83. if (*psz != PASSWORDMAGIC)
  84. *psz ^= PASSWORDMAGIC;
  85. }
  86. }
  87. }
  88. VOID
  89. CmEncodePasswordW(
  90. IN OUT WCHAR* pszPassword )
  91. /* Obfuscate 'pszPassword' in place to foil memory scans for passwords.
  92. **
  93. ** Returns Nothing
  94. */
  95. {
  96. if (pszPassword)
  97. {
  98. WCHAR* psz;
  99. ReverseSzW( pszPassword );
  100. for (psz = pszPassword; *psz != L'\0'; ++psz)
  101. {
  102. if (*psz != PASSWORDMAGIC)
  103. *psz ^= PASSWORDMAGIC;
  104. }
  105. }
  106. }
  107. VOID
  108. CmWipePasswordA(
  109. IN OUT CHAR* pszPassword )
  110. /* Zero out the memory occupied by a password.
  111. **
  112. ** Returns Nothing
  113. */
  114. {
  115. if (pszPassword)
  116. {
  117. CHAR* psz = pszPassword;
  118. //
  119. // We are assuming the string is NULL terminated, thus we just need to pass
  120. // the actual string length (converted to bytes) to be wiped. The is no need
  121. // to include the NULL character in the count.
  122. //
  123. psz = (CHAR*)CmSecureZeroMemory((PVOID)psz, lstrlenA(psz) * sizeof(CHAR));
  124. }
  125. }
  126. VOID
  127. CmWipePasswordW(
  128. IN OUT WCHAR* pszPassword )
  129. /* Zero out the memory occupied by a password.
  130. **
  131. ** Returns Nothing
  132. */
  133. {
  134. if (pszPassword)
  135. {
  136. WCHAR* psz = pszPassword;
  137. //
  138. // We are assuming the string is NULL terminated, thus we just need to pass
  139. // the actual string length (converted to bytes) to be wiped. The is no need
  140. // to include the NULL character in the count.
  141. //
  142. psz = (WCHAR*)CmSecureZeroMemory((PVOID)psz, lstrlenW(psz) * sizeof(WCHAR));
  143. }
  144. }
  145. //+----------------------------------------------------------------------------
  146. //
  147. // Function: CmSecureZeroMemory
  148. //
  149. // Synopsis: RtlSecureZeroMemory isn't available on all platforms so we took
  150. // its implementation.
  151. //
  152. // Arguments: ptr - memory pointer
  153. // cnt - size in bytes of memory to clear
  154. //
  155. // Returns: poniter to beginning of memory
  156. //
  157. //+----------------------------------------------------------------------------
  158. PVOID CmSecureZeroMemory(IN PVOID ptr, IN SIZE_T cnt)
  159. {
  160. if (ptr)
  161. {
  162. volatile char *vptr = (volatile char *)ptr;
  163. while (cnt)
  164. {
  165. *vptr = 0;
  166. vptr++;
  167. cnt--;
  168. }
  169. }
  170. return ptr;
  171. }
  172. // Only include this code in CMDial32.dll
  173. #ifdef _ICM_INC
  174. //+----------------------------------------------------------------------------
  175. // Class: CSecurePassword
  176. //
  177. // Function: CSecurePassword
  178. //
  179. // Synopsis: Constructor
  180. //
  181. // Arguments: none
  182. //
  183. // Returns: Nothing
  184. //
  185. // History: 11/05/2002 tomkel Created
  186. //
  187. //+----------------------------------------------------------------------------
  188. CSecurePassword::CSecurePassword()
  189. {
  190. this->Init();
  191. }
  192. //+----------------------------------------------------------------------------
  193. //
  194. // Function: ~CSecurePassword
  195. //
  196. // Synopsis: Destructor. Unloads DLL, tries to clear memory & free memory.
  197. // Makes sure we don't have a memory leak.
  198. //
  199. // Arguments: none
  200. //
  201. // Returns: Nothing
  202. //
  203. //+----------------------------------------------------------------------------
  204. CSecurePassword::~CSecurePassword()
  205. {
  206. this->UnInit();
  207. //
  208. // Assert if m_iAllocAndFreeCounter isn't zero. It means we are leaking memory.
  209. // Each GetPasswordWithAlloc call increments this
  210. // Each ClearAndFree call decrements this.
  211. //
  212. MYDBGASSERT(0 == m_iAllocAndFreeCounter);
  213. }
  214. //+----------------------------------------------------------------------------
  215. //
  216. // Function: Init
  217. //
  218. // Synopsis: Initializes member variables.
  219. //
  220. // Arguments: none
  221. //
  222. // Returns: Nothing
  223. //
  224. //+----------------------------------------------------------------------------
  225. VOID CSecurePassword::Init()
  226. {
  227. m_iAllocAndFreeCounter = 0;
  228. m_fIsLibAndFuncPtrsAvail = FALSE;
  229. m_pEncryptedPW = NULL;
  230. fnCryptProtectData = NULL;
  231. fnCryptUnprotectData = NULL;
  232. m_fIsEmptyString = TRUE;
  233. m_fIsHandleToPassword = FALSE;
  234. // By default just set it to PWLEN
  235. m_dwMaxDataLen = PWLEN;
  236. this->ClearMemberVars();
  237. }
  238. //+----------------------------------------------------------------------------
  239. //
  240. // Function: SetPassword
  241. //
  242. // Synopsis: We take this string that is passed in and store it
  243. // internally. Based on the OS it encrypts
  244. // or encodes it, thus we don't store it in clear. This method handles
  245. // 0 length strings, which can be used to clear the member
  246. // variable. If a RAS password handle (consists of 16 '*'),
  247. // there is no need for us to encrypt it. To optimize this
  248. // we set an member flag specifying that currently this
  249. // instance just hold a handle to a password. On downlevel
  250. // platforms we don't use expensive encryption calls, thus
  251. // the logic doesn't distinguish between a normal password
  252. // and a password handle.
  253. //
  254. // Arguments: szPassword - password in clear text.
  255. //
  256. // Returns: TRUE - if everything succeeded
  257. // FALSE - if something failed
  258. //
  259. //+----------------------------------------------------------------------------
  260. BOOL CSecurePassword::SetPassword(IN LPWSTR pszPassword)
  261. {
  262. BOOL fRetCode = FALSE;
  263. DWORD dwRetCode = ERROR_SUCCESS;
  264. DWORD dwPwLen = 0;
  265. //
  266. // OS_NT5 expands to a few function calls, so just cache the result and reuse it below
  267. //
  268. BOOL fIsNT5OrAbove = OS_NT5;
  269. //
  270. // If there is an allocated blob then free it first so we don't leak memory.
  271. //
  272. this->ClearMemberVars();
  273. m_fIsEmptyString = ((NULL == pszPassword) || (TEXT('\0') == pszPassword[0]));
  274. if (m_fIsEmptyString)
  275. {
  276. //
  277. // No need to continue, since password can be NULL the code below that compares
  278. // it to a handle (16 *s) would be dereferencing a NULL
  279. //
  280. m_fIsHandleToPassword = FALSE;
  281. return TRUE;
  282. }
  283. //
  284. // Check whether this is a handle to a password (****************)
  285. //
  286. m_fIsHandleToPassword = (fIsNT5OrAbove && (0 == lstrcmpW(c_pszSavedPasswordToken, pszPassword)));
  287. //
  288. // If the internal flag is set, there is no need to encrypt or decrypt this string.
  289. //
  290. if (m_fIsHandleToPassword)
  291. {
  292. return TRUE;
  293. }
  294. //
  295. // Make sure the password that is being encrypted is shorter than the allowed maximum
  296. //
  297. dwPwLen = lstrlenU(pszPassword);
  298. if (m_dwMaxDataLen < dwPwLen)
  299. {
  300. return FALSE;
  301. }
  302. if (fIsNT5OrAbove)
  303. {
  304. m_pEncryptedPW = (DATA_BLOB*)CmMalloc(sizeof(DATA_BLOB));
  305. if (m_pEncryptedPW)
  306. {
  307. dwRetCode = this->EncodePassword((dwPwLen + 1) * sizeof(WCHAR), (PBYTE)pszPassword, m_pEncryptedPW);
  308. if (ERROR_SUCCESS == dwRetCode)
  309. {
  310. fRetCode = TRUE;
  311. }
  312. else
  313. {
  314. //
  315. // Free the allocated DATA_BLOB so that decryption doesn't cause issue in case caller
  316. // ends up calling it. And reset internal flags.
  317. //
  318. this->ClearMemberVars();
  319. m_fIsEmptyString = TRUE;
  320. m_fIsHandleToPassword = FALSE;
  321. CMTRACE1(TEXT("CSecurePassword::SetPassword - this->EncodePassword failed. 0x%x"), dwRetCode);
  322. }
  323. }
  324. }
  325. else
  326. {
  327. //
  328. // Downlevel (Win9x, NT4) we don't support encryption
  329. //
  330. lstrcpynU(m_tszPassword, pszPassword, CELEMS(m_tszPassword));
  331. CmEncodePassword(m_tszPassword);
  332. fRetCode = TRUE;
  333. }
  334. MYDBGASSERT(fRetCode);
  335. return fRetCode;
  336. }
  337. //+----------------------------------------------------------------------------
  338. //
  339. // Function: GetPasswordWithAlloc
  340. //
  341. // Synopsis: Allocates a buffer and copies the clear-text password into it.
  342. // Based on the OS it decrypts or decodes it since it's not stored
  343. // in clear. If the internal password is an empty string we allocate
  344. // an empty string buffer. This is done for consistency since the caller
  345. // needs to call our free method so memory isn't leaked. If we are storing
  346. // a RAS password handle (consists of 16 '*') we actually didn't store it,
  347. // but only set our internal flag. In this case we need to allocate a buffer
  348. // with 16 * and return it. On downlevel platforms we don't use expensive
  349. // decryption calls, thus the logic doesn't distinguish between a
  350. // normal password and a password handle.
  351. //
  352. // Arguments: pszClearPw - holds a pointer to a buffer that was allocated by this
  353. // class.
  354. // pcbClearPw - hold the size of the allocated buffer in bytes
  355. //
  356. // Returns: TRUE - if everything succeeded
  357. // FALSE - if something failed
  358. //
  359. //+----------------------------------------------------------------------------
  360. BOOL CSecurePassword::GetPasswordWithAlloc(OUT LPWSTR* pszClearPw, OUT DWORD* pcbClearPw)
  361. {
  362. BOOL fRetCode = FALSE;
  363. DWORD dwRetCode = ERROR_SUCCESS;
  364. DWORD cbData = 0;
  365. PBYTE pbData = NULL;
  366. if ((NULL == pszClearPw) || (NULL == pcbClearPw))
  367. {
  368. MYDBGASSERT(FALSE);
  369. return FALSE;
  370. }
  371. *pszClearPw = NULL;
  372. *pcbClearPw = 0;
  373. if (OS_NT5)
  374. {
  375. if (m_fIsEmptyString)
  376. {
  377. //
  378. // In case there is nothing saved in this class, just allocate an empty string
  379. // and return it back. This at least doesn't have to decrypt and empty string.
  380. //
  381. DWORD cbLen = sizeof(WCHAR);
  382. LPWSTR szTemp = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, cbLen);
  383. if (szTemp)
  384. {
  385. *pszClearPw = szTemp;
  386. *pcbClearPw = cbLen;
  387. fRetCode = TRUE;
  388. m_iAllocAndFreeCounter++;
  389. }
  390. }
  391. else
  392. {
  393. //
  394. // Check if this instance is just a handle to a RAS password (16 *)
  395. // If so, then just allocate that string and return it to the caller,
  396. // otherwise proceed normally and decrypt our blob.
  397. //
  398. if (m_fIsHandleToPassword)
  399. {
  400. size_t nLen = lstrlenW(c_pszSavedPasswordToken) + 1;
  401. DWORD cbLen = nLen * sizeof(WCHAR);
  402. LPWSTR szTemp = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, cbLen);
  403. if (szTemp)
  404. {
  405. lstrcpynW(szTemp, c_pszSavedPasswordToken, nLen);
  406. *pszClearPw = szTemp;
  407. *pcbClearPw = cbLen;
  408. fRetCode = TRUE;
  409. m_iAllocAndFreeCounter++;
  410. }
  411. }
  412. else
  413. {
  414. if (m_pEncryptedPW)
  415. {
  416. dwRetCode = this->DecodePassword(m_pEncryptedPW, &cbData, &pbData);
  417. if ((NO_ERROR == dwRetCode) && pbData && cbData)
  418. {
  419. *pszClearPw = (LPWSTR)pbData;
  420. *pcbClearPw = cbData;
  421. fRetCode = TRUE;
  422. m_iAllocAndFreeCounter++;
  423. }
  424. }
  425. }
  426. }
  427. }
  428. else
  429. {
  430. //
  431. // Downlevel (Win9x, NT4) doesn't support 16 *
  432. //
  433. size_t nLen = lstrlenU(m_tszPassword) + 1;
  434. LPTSTR pszBuffer = (LPWSTR)CmMalloc(nLen * sizeof(TCHAR));
  435. if (pszBuffer)
  436. {
  437. //
  438. // Copy our encoded buffer to the newly allocated buffer
  439. // We can do this because d/encoding is done in place
  440. //
  441. lstrcpynU(pszBuffer, m_tszPassword, nLen);
  442. //
  443. // Decode the outgoing buffer
  444. //
  445. CmDecodePassword(pszBuffer);
  446. *pszClearPw = (LPWSTR)pszBuffer;
  447. *pcbClearPw = nLen * sizeof(TCHAR);
  448. fRetCode = TRUE;
  449. m_iAllocAndFreeCounter++;
  450. }
  451. }
  452. MYDBGASSERT(fRetCode);
  453. return fRetCode;
  454. }
  455. //+----------------------------------------------------------------------------
  456. //
  457. // Function: ClearAndFree
  458. //
  459. // Synopsis: Clear then free a buffer that was allocated by this class. Notice that
  460. // on downlevel platforms the way a buffer is freed differs. That
  461. // is because encrypting and decrypting needs us to free it
  462. // using LocalFree. For downlevel platforms we chose CM's standard
  463. // way of allocating memory (CmMalloc) and it now needs to be
  464. // freed using CmFree.
  465. //
  466. // Arguments: pszClearPw - holds a pointer to a buffer that was allocated by this
  467. // class.
  468. // cbClearPw - size of the allocated buffer in bytes
  469. //
  470. // Returns: TRUE - if everything succeeded
  471. // FALSE - if something failed
  472. //
  473. //+----------------------------------------------------------------------------
  474. VOID CSecurePassword::ClearAndFree(IN OUT LPWSTR* pszClearPw, IN DWORD cbClearPw)
  475. {
  476. if ((NULL == pszClearPw) || (0 == cbClearPw))
  477. {
  478. return;
  479. }
  480. if (NULL == *pszClearPw)
  481. {
  482. return;
  483. }
  484. CmSecureZeroMemory(*pszClearPw, cbClearPw);
  485. if (OS_NT5)
  486. {
  487. //
  488. // Uses LocalFree because CryptProtectData requires this way
  489. // to free its memory
  490. //
  491. LocalFree(*pszClearPw);
  492. }
  493. else
  494. {
  495. //
  496. // We used CmMalloc to allocate so we need to call CmFree
  497. //
  498. CmFree(*pszClearPw);
  499. }
  500. *pszClearPw = NULL;
  501. m_iAllocAndFreeCounter--;
  502. return;
  503. }
  504. //+----------------------------------------------------------------------------
  505. //
  506. // Function: ClearMemberVars
  507. //
  508. // Synopsis: Clears our member variables. Notice that we only clear the
  509. // passwords & member variables. This doesn't mean that m_fIsEmptyString
  510. // should be set. This needs to be a private method
  511. // because it doesn't reset the empty or password handle flags. Thus
  512. // outside callers should NOT use this, because it would create an invalid
  513. // state.
  514. //
  515. // Arguments: none
  516. //
  517. // Returns: none
  518. //
  519. //+----------------------------------------------------------------------------
  520. VOID CSecurePassword::ClearMemberVars()
  521. {
  522. if (OS_NT5)
  523. {
  524. if (m_pEncryptedPW)
  525. {
  526. this->FreePassword(m_pEncryptedPW);
  527. CmFree(m_pEncryptedPW);
  528. m_pEncryptedPW = NULL;
  529. }
  530. }
  531. else
  532. {
  533. //
  534. // Zero out the password buffer
  535. //
  536. CmSecureZeroMemory((PVOID)m_tszPassword, sizeof(m_tszPassword));
  537. }
  538. }
  539. //+----------------------------------------------------------------------------
  540. //
  541. // Function: UnInit
  542. //
  543. // Synopsis: Unloads DLL, clear and frees memory.
  544. //
  545. // Arguments: none
  546. //
  547. // Returns: none
  548. //
  549. //+----------------------------------------------------------------------------
  550. VOID CSecurePassword::UnInit()
  551. {
  552. this->UnloadCrypt32();
  553. this->ClearMemberVars();
  554. m_fIsHandleToPassword = FALSE;
  555. m_fIsEmptyString = FALSE;
  556. }
  557. //+----------------------------------------------------------------------------
  558. //
  559. // Function: UnloadCrypt32
  560. //
  561. // Synopsis: Unloads DLL
  562. //
  563. // Arguments: none
  564. //
  565. // Returns: none
  566. //
  567. //+----------------------------------------------------------------------------
  568. VOID CSecurePassword::UnloadCrypt32()
  569. {
  570. fnCryptProtectData = NULL;
  571. fnCryptUnprotectData = NULL;
  572. m_dllCrypt32.Unload();
  573. m_fIsLibAndFuncPtrsAvail = FALSE;
  574. }
  575. //+----------------------------------------------------------------------------
  576. //
  577. // Function: EncodePassword
  578. //
  579. // Synopsis: Encrypts data using CryptProtectData
  580. //
  581. // Arguments: cbPassword - size of buffer in bytes
  582. // pbPassword - pointer to a buffer to encrypt
  583. // pDataBlobPassword - pointer to an allocated DATA_BLOB structure
  584. //
  585. // Returns: none
  586. //
  587. //+----------------------------------------------------------------------------
  588. DWORD CSecurePassword::EncodePassword(IN DWORD cbPassword,
  589. IN PBYTE pbPassword,
  590. OUT DATA_BLOB* pDataBlobPassword)
  591. {
  592. DWORD dwErr = NO_ERROR;
  593. DATA_BLOB DataBlobIn;
  594. if(NULL == pDataBlobPassword)
  595. {
  596. dwErr = E_INVALIDARG;
  597. CMTRACE(TEXT("CSecurePassword::EncodePassword - NULL == pDataBlobPassword"));
  598. goto done;
  599. }
  600. if( (0 == cbPassword)
  601. || (NULL == pbPassword))
  602. {
  603. //
  604. // nothing to encrypt.
  605. //
  606. dwErr = E_INVALIDARG;
  607. CMTRACE(TEXT("CSecurePassword::EncodePassword - E_INVALIDARG"));
  608. goto done;
  609. }
  610. //
  611. // If Crypt32.DLL is not loaded, try to loaded and get the
  612. // function pointers.
  613. //
  614. if (FALSE == m_fIsLibAndFuncPtrsAvail)
  615. {
  616. if (FALSE == this->LoadCrypt32AndGetFuncPtrs())
  617. {
  618. //
  619. // This failed, thus we can't continue. We should free memory.
  620. //
  621. this->ClearMemberVars();
  622. m_fIsEmptyString = TRUE;
  623. m_fIsHandleToPassword = FALSE;
  624. dwErr = ERROR_DLL_INIT_FAILED;
  625. CMTRACE(TEXT("CSecurePassword::EncodePassword - this-> LoadCrypt32AndGetFuncPtrs failed."));
  626. goto done;
  627. }
  628. }
  629. ZeroMemory(pDataBlobPassword, sizeof(DATA_BLOB));
  630. DataBlobIn.cbData = cbPassword;
  631. DataBlobIn.pbData = pbPassword;
  632. if (fnCryptProtectData)
  633. {
  634. LPCWSTR wszDesc[] = {TEXT("Readable description of data.")};
  635. LPWSTR pszDesc = NULL;
  636. if (OS_W2K)
  637. {
  638. //
  639. // The crypto API needs this, but only on Win2K
  640. //
  641. pszDesc = (LPWSTR)wszDesc;
  642. }
  643. if(!fnCryptProtectData(
  644. &DataBlobIn,
  645. (LPCWSTR)pszDesc,
  646. NULL,
  647. NULL,
  648. NULL,
  649. CRYPTPROTECT_UI_FORBIDDEN,
  650. pDataBlobPassword))
  651. {
  652. dwErr = GetLastError();
  653. CMTRACE1(TEXT("CSecurePassword::EncodePassword - fnCryptProtectData failed. 0x%x"), dwErr);
  654. goto done;
  655. }
  656. }
  657. else
  658. {
  659. CMTRACE(TEXT("CSecurePassword::EncodePassword - ERROR_FUNCTION_NOT_CALLED"));
  660. dwErr = ERROR_FUNCTION_NOT_CALLED;
  661. }
  662. done:
  663. MYDBGASSERT(NO_ERROR == dwErr);
  664. return dwErr;
  665. }
  666. //+----------------------------------------------------------------------------
  667. //
  668. // Function: DecodePassword
  669. //
  670. // Synopsis: Decrypts data using CryptUnprotectData
  671. //
  672. // Arguments: pDataBlobPassword - pointer to a DATA_BLOB structure to be decrypted
  673. // cbPassword - pointer that holds the size of buffer in bytes
  674. // pbPassword - pointer to a buffer to encrypt
  675. //
  676. //
  677. // Returns: none
  678. //
  679. //+----------------------------------------------------------------------------
  680. DWORD CSecurePassword::DecodePassword(IN DATA_BLOB* pDataBlobPassword,
  681. OUT DWORD* pcbPassword,
  682. OUT PBYTE* ppbPassword)
  683. {
  684. DWORD dwErr = NO_ERROR;
  685. DATA_BLOB DataOut;
  686. if( (NULL == pDataBlobPassword)
  687. || (NULL == pcbPassword)
  688. || (NULL == ppbPassword))
  689. {
  690. dwErr = E_INVALIDARG;
  691. goto done;
  692. }
  693. *pcbPassword = 0;
  694. *ppbPassword = NULL;
  695. if( (NULL == pDataBlobPassword->pbData)
  696. || (0 == pDataBlobPassword->cbData))
  697. {
  698. //
  699. // nothing to decrypt. Just return success.
  700. //
  701. goto done;
  702. }
  703. //
  704. // If Crypt32.DLL is not loaded, try to loaded and get the
  705. // function pointers.
  706. //
  707. if (FALSE == m_fIsLibAndFuncPtrsAvail)
  708. {
  709. if (FALSE == this->LoadCrypt32AndGetFuncPtrs())
  710. {
  711. //
  712. // This failed, thus we can't continue. We should free memory.
  713. //
  714. this->ClearMemberVars();
  715. m_fIsEmptyString = TRUE;
  716. m_fIsHandleToPassword = FALSE;
  717. dwErr = ERROR_DLL_INIT_FAILED;
  718. goto done;
  719. }
  720. }
  721. ZeroMemory(&DataOut, sizeof(DATA_BLOB));
  722. if (fnCryptUnprotectData)
  723. {
  724. if(!fnCryptUnprotectData(
  725. pDataBlobPassword,
  726. NULL,
  727. NULL,
  728. NULL,
  729. NULL,
  730. CRYPTPROTECT_UI_FORBIDDEN,
  731. &DataOut))
  732. {
  733. dwErr = GetLastError();
  734. goto done;
  735. }
  736. dwErr = NO_ERROR;
  737. *pcbPassword = DataOut.cbData;
  738. *ppbPassword = DataOut.pbData;
  739. }
  740. else
  741. {
  742. dwErr = ERROR_FUNCTION_NOT_CALLED;
  743. }
  744. done:
  745. MYDBGASSERT(NO_ERROR == dwErr);
  746. return dwErr;
  747. }
  748. //+----------------------------------------------------------------------------
  749. //
  750. // Function: FreePassword
  751. //
  752. // Synopsis: Frees data in DATA_BLOB structure
  753. //
  754. // Arguments: pDBPassword - pointer to a DATA_BLOB structure
  755. //
  756. // Returns: none
  757. //
  758. //+----------------------------------------------------------------------------
  759. VOID CSecurePassword::FreePassword(IN DATA_BLOB *pDBPassword)
  760. {
  761. if(NULL == pDBPassword)
  762. {
  763. return;
  764. }
  765. if(NULL != pDBPassword->pbData)
  766. {
  767. CmSecureZeroMemory(pDBPassword->pbData, pDBPassword->cbData);
  768. LocalFree(pDBPassword->pbData);
  769. }
  770. //
  771. // Clear sensitive data.
  772. //
  773. CmSecureZeroMemory(pDBPassword, sizeof(DATA_BLOB));
  774. }
  775. //+----------------------------------------------------------------------------
  776. //
  777. // Function: LoadCrypt32AndGetFuncPtrs
  778. //
  779. // Synopsis: Loads crypt32.dll and gets function pointer to needed methods
  780. //
  781. // Arguments: none
  782. //
  783. // Returns: TRUE - if .DLL was loaded and function pointers were retrieved
  784. // FALSE - when an error was encountered
  785. //
  786. //+----------------------------------------------------------------------------
  787. BOOL CSecurePassword::LoadCrypt32AndGetFuncPtrs()
  788. {
  789. BOOL fRetVal = FALSE;
  790. if (OS_NT5)
  791. {
  792. if (FALSE == m_fIsLibAndFuncPtrsAvail)
  793. {
  794. fRetVal = m_dllCrypt32.Load(TEXT("crypt32.dll"));
  795. if (fRetVal)
  796. {
  797. fnCryptProtectData = (fnCryptProtectDataFunc)m_dllCrypt32.GetProcAddress("CryptProtectData");
  798. fnCryptUnprotectData = (fnCryptUnprotectDataFunc)m_dllCrypt32.GetProcAddress("CryptUnprotectData");
  799. if (fnCryptProtectData && fnCryptUnprotectData)
  800. {
  801. CMTRACE(TEXT("CSecurePassword::LoadCrypt32AndGetFuncPtrs - success"));
  802. m_fIsLibAndFuncPtrsAvail = TRUE;
  803. fRetVal = TRUE;
  804. }
  805. else
  806. {
  807. CMTRACE(TEXT("CSecurePassword::LoadCrypt32AndGetFuncPtrs - missing function pointers"));
  808. this->UnloadCrypt32();
  809. }
  810. }
  811. else
  812. {
  813. CMTRACE(TEXT("CSecurePassword::LoadCrypt32AndGetFuncPtrs - m_dllCrypt32.Load failed"));
  814. }
  815. }
  816. else
  817. {
  818. fRetVal = m_fIsLibAndFuncPtrsAvail;
  819. }
  820. }
  821. MYDBGASSERT(fRetVal);
  822. return fRetVal;
  823. }
  824. //+----------------------------------------------------------------------------
  825. //
  826. // Function: IsEmptyString
  827. //
  828. // Synopsis: Used as a shortcut so we don't have to encrypt/decrypt in case
  829. // we stored an empty string.
  830. //
  831. // Arguments: none
  832. //
  833. // Returns: TRUE - if instance is suppose to be holding an empty string
  834. // FALSE - if currenttly saved string is not empty
  835. //
  836. //+----------------------------------------------------------------------------
  837. BOOL CSecurePassword::IsEmptyString()
  838. {
  839. return m_fIsEmptyString;
  840. }
  841. //+----------------------------------------------------------------------------
  842. //
  843. // Function: IsHandleToPassword
  844. //
  845. // Synopsis: Used as a shortcut so we don't have to encrypt/decrypt in case
  846. // we stored a handle to a RAS password (16 *).
  847. //
  848. // Arguments: none
  849. //
  850. // Returns: TRUE - if instance is suppose to be holding ****************
  851. // FALSE - if currenttly saved string is a normal password
  852. //
  853. //+----------------------------------------------------------------------------
  854. BOOL CSecurePassword::IsHandleToPassword()
  855. {
  856. return m_fIsHandleToPassword;
  857. }
  858. //+----------------------------------------------------------------------------
  859. //
  860. // Function: SetMaxDataLenToProtect
  861. //
  862. // Synopsis: Set the maximum length password to protect. This value will be
  863. // checked when encrypting a password.
  864. //
  865. // Arguments: dwMaxDataLen - maximum password length in characters
  866. //
  867. // Returns: Nothing
  868. //
  869. //+----------------------------------------------------------------------------
  870. VOID CSecurePassword::SetMaxDataLenToProtect(DWORD dwMaxDataLen)
  871. {
  872. m_dwMaxDataLen = dwMaxDataLen;
  873. }
  874. //+----------------------------------------------------------------------------
  875. //
  876. // Function: GetMaxDataLenToProtect
  877. //
  878. // Synopsis: Get the maximum length password that this class can protect.
  879. //
  880. // Arguments: none
  881. //
  882. // Returns: DWORD - maximum password length
  883. //
  884. //+----------------------------------------------------------------------------
  885. DWORD CSecurePassword::GetMaxDataLenToProtect()
  886. {
  887. return m_dwMaxDataLen;
  888. }
  889. #endif // _ICM_INC