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

1859 lines
38 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. salemlib.cpp
  5. Abstract:
  6. All Salem related function, this library is shared by termsrv.dll
  7. and salem sessmgr.exe
  8. Author:
  9. HueiWang 4/26/2000
  10. --*/
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <ntlsa.h>
  15. #include <windows.h>
  16. #include <ntlsapi.h>
  17. #include <stdio.h>
  18. #include <rpc.h>
  19. #include <rpcdce.h>
  20. #include <wincrypt.h>
  21. #include <regapi.h>
  22. #include "winsta.h"
  23. #include "tsremdsk.h"
  24. #include "base64.h"
  25. #ifdef AllocMemory
  26. #undef AllocMemory
  27. #undef FreeMemory
  28. #endif
  29. #define AllocMemory(size) LocalAlloc(LPTR, size)
  30. #define FreeMemory(ptr) LocalFree(ptr)
  31. //
  32. // Global Crypto provider
  33. //
  34. HCRYPTPROV gm_hCryptProv = NULL; // Crypto provider
  35. //
  36. // CryptEncrypt()/CryptDecrypt() not thread safe
  37. //
  38. HANDLE gm_hMutex = NULL;
  39. extern DWORD
  40. StoreKeyWithLSA(
  41. IN PWCHAR pwszKeyName,
  42. IN BYTE * pbKey,
  43. IN DWORD cbKey
  44. );
  45. extern DWORD
  46. RetrieveKeyFromLSA(
  47. IN PWCHAR pwszKeyName,
  48. OUT PBYTE * ppbKey,
  49. OUT DWORD * pcbKey
  50. );
  51. void
  52. EncryptUnlock();
  53. DWORD
  54. EncryptLock();
  55. void
  56. InitLsaString(
  57. IN OUT PLSA_UNICODE_STRING LsaString,
  58. IN LPWSTR String
  59. )
  60. /*++
  61. Routine Description:
  62. Initialize LSA unicode string.
  63. Parameters:
  64. LsaString : Pointer to LSA_UNICODE_STRING to be initialized.
  65. String : String to initialize LsaString.
  66. Returns:
  67. None.
  68. Note:
  69. Refer to LSA_UNICODE_STRING
  70. --*/
  71. {
  72. DWORD StringLength;
  73. if( NULL == String )
  74. {
  75. LsaString->Buffer = NULL;
  76. LsaString->Length = 0;
  77. LsaString->MaximumLength = 0;
  78. return;
  79. }
  80. StringLength = lstrlenW( String );
  81. LsaString->Buffer = String;
  82. LsaString->Length = ( USHORT ) StringLength * sizeof( WCHAR );
  83. LsaString->MaximumLength=( USHORT )( StringLength + 1 ) * sizeof( WCHAR );
  84. }
  85. DWORD
  86. OpenPolicy(
  87. IN LPWSTR ServerName,
  88. IN DWORD DesiredAccess,
  89. OUT PLSA_HANDLE PolicyHandle
  90. )
  91. /*++
  92. Routine Description:
  93. Create/return a LSA policy handle.
  94. Parameters:
  95. ServerName : Name of server, refer to LsaOpenPolicy().
  96. DesiredAccess : Desired access level, refer to LsaOpenPolicy().
  97. PolicyHandle : Return PLSA_HANDLE.
  98. Returns:
  99. ERROR_SUCCESS or LSA error code
  100. --*/
  101. {
  102. LSA_OBJECT_ATTRIBUTES ObjectAttributes;
  103. LSA_UNICODE_STRING ServerString;
  104. PLSA_UNICODE_STRING Server;
  105. //
  106. // Always initialize the object attributes to all zeroes.
  107. //
  108. ZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) );
  109. if( NULL != ServerName )
  110. {
  111. //
  112. // Make a LSA_UNICODE_STRING out of the LPWSTR passed in
  113. //
  114. InitLsaString( &ServerString, ServerName );
  115. Server = &ServerString;
  116. }
  117. else
  118. {
  119. Server = NULL;
  120. }
  121. //
  122. // Attempt to open the policy.
  123. //
  124. return( LsaOpenPolicy(
  125. Server,
  126. &ObjectAttributes,
  127. DesiredAccess,
  128. PolicyHandle ) );
  129. }
  130. DWORD
  131. StoreKeyWithLSA(
  132. IN PWCHAR pwszKeyName,
  133. IN BYTE * pbKey,
  134. IN DWORD cbKey
  135. )
  136. /*++
  137. Routine Description:
  138. Save private data to LSA.
  139. Parameters:
  140. pwszKeyName : Name of the key this data going to be stored under.
  141. pbKey : Binary data to be saved.
  142. cbKey : Size of binary data.
  143. Returns:
  144. ERROR_SUCCESS
  145. ERROR_INVALID_PARAMETER.
  146. LSA return code
  147. --*/
  148. {
  149. LSA_HANDLE PolicyHandle;
  150. UNICODE_STRING SecretKeyName;
  151. UNICODE_STRING SecretData;
  152. DWORD Status;
  153. if( ( NULL == pwszKeyName ) )
  154. {
  155. return( ERROR_INVALID_PARAMETER );
  156. }
  157. //
  158. // setup the UNICODE_STRINGs for the call.
  159. //
  160. InitLsaString(
  161. &SecretKeyName,
  162. pwszKeyName
  163. );
  164. SecretData.Buffer = ( LPWSTR )pbKey;
  165. SecretData.Length = ( USHORT )cbKey;
  166. SecretData.MaximumLength = ( USHORT )cbKey;
  167. Status = OpenPolicy(
  168. NULL,
  169. POLICY_CREATE_SECRET,
  170. &PolicyHandle
  171. );
  172. if( Status != ERROR_SUCCESS )
  173. {
  174. return LsaNtStatusToWinError(Status);
  175. }
  176. Status = LsaStorePrivateData(
  177. PolicyHandle,
  178. &SecretKeyName,
  179. &SecretData
  180. );
  181. LsaClose(PolicyHandle);
  182. return LsaNtStatusToWinError(Status);
  183. }
  184. DWORD
  185. RetrieveKeyFromLSA(
  186. IN PWCHAR pwszKeyName,
  187. OUT PBYTE * ppbKey,
  188. OUT DWORD * pcbKey
  189. )
  190. /*++
  191. Routine Description:
  192. Retrieve private data previously stored with StoreKeyWithLSA().
  193. Parameters:
  194. pwszKeyName : Name of the key.
  195. ppbKey : Pointer to PBYTE to receive binary data.
  196. pcbKey : Size of binary data.
  197. Returns:
  198. ERROR_SUCCESS
  199. ERROR_INVALID_PARAMETER.
  200. ERROR_FILE_NOT_FOUND
  201. LSA return code
  202. --*/
  203. {
  204. LSA_HANDLE PolicyHandle;
  205. UNICODE_STRING SecretKeyName;
  206. UNICODE_STRING *pSecretData;
  207. DWORD Status;
  208. if( ( NULL == pwszKeyName ) || ( NULL == ppbKey ) || ( NULL == pcbKey ) )
  209. {
  210. SetLastError( ERROR_INVALID_PARAMETER );
  211. return( ERROR_INVALID_PARAMETER );
  212. }
  213. //
  214. // setup the UNICODE_STRINGs for the call.
  215. //
  216. InitLsaString(
  217. &SecretKeyName,
  218. pwszKeyName
  219. );
  220. Status = OpenPolicy(
  221. NULL,
  222. POLICY_GET_PRIVATE_INFORMATION,
  223. &PolicyHandle
  224. );
  225. if( Status != ERROR_SUCCESS )
  226. {
  227. SetLastError( LsaNtStatusToWinError(Status) );
  228. return GetLastError();
  229. }
  230. Status = LsaRetrievePrivateData(
  231. PolicyHandle,
  232. &SecretKeyName,
  233. &pSecretData
  234. );
  235. LsaClose( PolicyHandle );
  236. if( Status != ERROR_SUCCESS )
  237. {
  238. SetLastError( LsaNtStatusToWinError(Status) );
  239. return GetLastError();
  240. }
  241. if(pSecretData != NULL && pSecretData->Length)
  242. {
  243. *ppbKey = (LPBYTE)AllocMemory( pSecretData->Length );
  244. if( *ppbKey )
  245. {
  246. *pcbKey = pSecretData->Length;
  247. CopyMemory( *ppbKey, pSecretData->Buffer, pSecretData->Length );
  248. Status = ERROR_SUCCESS;
  249. }
  250. else
  251. {
  252. Status = GetLastError();
  253. }
  254. }
  255. else
  256. {
  257. Status = ERROR_FILE_NOT_FOUND;
  258. SetLastError( Status );
  259. *pcbKey = 0;
  260. *ppbKey = NULL;
  261. }
  262. if (pSecretData != NULL) {
  263. ZeroMemory( pSecretData->Buffer, pSecretData->Length );
  264. LsaFreeMemory( pSecretData );
  265. }
  266. return Status;
  267. }
  268. DWORD
  269. TSSetEncryptionKey(
  270. IN PBYTE pbData,
  271. IN DWORD cbData
  272. )
  273. /*++
  274. Routine Description:
  275. Cache random password that use to deriving encryption cycle key.
  276. Parameters:
  277. pbData :
  278. cbData :
  279. Returns:
  280. ERROR_SUCCESS or error code
  281. --*/
  282. {
  283. DWORD status;
  284. if( !pbData || cbData == 0 )
  285. {
  286. status = ERROR_INVALID_PARAMETER;
  287. goto CLEANUPANDEXIT;
  288. }
  289. status = EncryptLock();
  290. if( ERROR_SUCCESS == status )
  291. {
  292. //
  293. // Load password to derive session encryption key from LSA
  294. //
  295. status = StoreKeyWithLSA(
  296. SALEMHELPASSISTANTACCOUNT_ENCRYPTIONKEY,
  297. pbData,
  298. cbData
  299. );
  300. EncryptUnlock();
  301. }
  302. CLEANUPANDEXIT:
  303. return status;
  304. }
  305. DWORD
  306. TSGetEncryptionKey(
  307. OUT PBYTE* ppbData,
  308. OUT DWORD* pcbData
  309. )
  310. /*++
  311. Routine Description:
  312. Cache random password that use to deriving encryption cycle key.
  313. Parameters:
  314. pbData :
  315. cbData :
  316. Returns:
  317. ERROR_SUCCESS or error code
  318. --*/
  319. {
  320. DWORD status;
  321. if( !ppbData || !pcbData )
  322. {
  323. status = ERROR_INVALID_PARAMETER;
  324. goto CLEANUPANDEXIT;
  325. }
  326. status = EncryptLock();
  327. if( ERROR_SUCCESS == status )
  328. {
  329. //
  330. // Load password to derive session encryption key from LSA
  331. //
  332. status = RetrieveKeyFromLSA(
  333. SALEMHELPASSISTANTACCOUNT_ENCRYPTIONKEY,
  334. ppbData,
  335. pcbData
  336. );
  337. EncryptUnlock();
  338. }
  339. CLEANUPANDEXIT:
  340. return status;
  341. }
  342. DWORD
  343. TSGetHelpAssistantAccountPassword(
  344. OUT LPWSTR* ppszAccPwd
  345. )
  346. /*++
  347. --*/
  348. {
  349. DWORD cbHelpAccPwd = 0;
  350. DWORD Status;
  351. Status = RetrieveKeyFromLSA(
  352. SALEMHELPASSISTANTACCOUNT_PASSWORDKEY,
  353. (PBYTE *)ppszAccPwd,
  354. &cbHelpAccPwd
  355. );
  356. if( ERROR_SUCCESS != Status )
  357. {
  358. // password is not set, assuming no help
  359. Status = ERROR_INVALID_ACCESS;
  360. }
  361. return Status;
  362. }
  363. DWORD
  364. TSGetHelpAssistantAccountName(
  365. OUT LPWSTR* ppszAccDomain,
  366. OUT LPWSTR* ppszAcctName
  367. )
  368. /*++
  369. Routine Description:
  370. Get HelpAssistant account name.
  371. Parameters:
  372. ppszAcctName : Pointer to LPWSTR to receive account name, use LocalFree()
  373. to free the buffer.
  374. Returns:
  375. ERROR_SUCCESS or error code
  376. --*/
  377. {
  378. LPWSTR pszHelpAcctName = NULL;
  379. LPWSTR pszHelpAcctDomain = NULL;
  380. DWORD cbHelpAcctName = 0;
  381. DWORD cbHelpAcctDomain = 0;
  382. SID_NAME_USE sidUse;
  383. DWORD Status;
  384. BOOL bSuccess;
  385. PSID pLsaHelpAccSid = NULL;
  386. DWORD cbLsaHelpAccSid = 0;
  387. //
  388. // Retrieve HelpAccount SID we cached in LSA
  389. Status = RetrieveKeyFromLSA(
  390. SALEMHELPASSISTANTACCOUNT_SIDKEY,
  391. (PBYTE *)&pLsaHelpAccSid,
  392. &cbLsaHelpAccSid
  393. );
  394. if( ERROR_SUCCESS != Status )
  395. {
  396. // Salem is not installed or not active on this machine
  397. goto CLEANUPANDEXIT;
  398. }
  399. //
  400. // Lookup account name from SID
  401. //
  402. bSuccess = LookupAccountSid(
  403. NULL,
  404. pLsaHelpAccSid,
  405. NULL,
  406. &cbHelpAcctName,
  407. NULL,
  408. &cbHelpAcctDomain,
  409. &sidUse
  410. );
  411. if( bSuccess == FALSE && ERROR_NONE_MAPPED == GetLastError() )
  412. {
  413. // Can't retrieve either because network error or account
  414. // does not exist, error out.
  415. Status = ERROR_FILE_NOT_FOUND;
  416. goto CLEANUPANDEXIT;
  417. }
  418. pszHelpAcctName = (LPTSTR)AllocMemory( (cbHelpAcctName+1)*sizeof(WCHAR) );
  419. pszHelpAcctDomain = (LPTSTR)AllocMemory( (cbHelpAcctDomain+1)*sizeof(WCHAR) );
  420. if( NULL == pszHelpAcctName || NULL == pszHelpAcctDomain )
  421. {
  422. Status = ERROR_OUTOFMEMORY;
  423. goto CLEANUPANDEXIT;
  424. }
  425. bSuccess = LookupAccountSid(
  426. NULL,
  427. pLsaHelpAccSid,
  428. pszHelpAcctName,
  429. &cbHelpAcctName,
  430. pszHelpAcctDomain,
  431. &cbHelpAcctDomain,
  432. &sidUse
  433. );
  434. if( FALSE == bSuccess )
  435. {
  436. Status = GetLastError();
  437. goto CLEANUPANDEXIT;
  438. }
  439. *ppszAcctName = pszHelpAcctName;
  440. *ppszAccDomain = pszHelpAcctDomain;
  441. // don't free account name.
  442. pszHelpAcctName = NULL;
  443. pszHelpAcctDomain = NULL;
  444. CLEANUPANDEXIT:
  445. if( NULL != pLsaHelpAccSid )
  446. {
  447. ZeroMemory( pLsaHelpAccSid, cbLsaHelpAccSid );
  448. FreeMemory( pLsaHelpAccSid );
  449. }
  450. if( NULL != pszHelpAcctDomain )
  451. {
  452. FreeMemory( pszHelpAcctDomain );
  453. }
  454. if( NULL != pszHelpAcctName )
  455. {
  456. FreeMemory(pszHelpAcctName);
  457. }
  458. return Status;
  459. }
  460. BOOL
  461. TSIsMachineInHelpMode()
  462. /*++
  463. Routine Description:
  464. Return if machine is in GetHelp mode
  465. Parameters:
  466. None.
  467. Returns:
  468. TRUE/FALSE
  469. --*/
  470. {
  471. //
  472. // machine can only be in help mode if we have some
  473. // password to derive session encryption key, if
  474. // no pending help session exist, sessmgr will end
  475. // encryption cycle.
  476. return TSHelpAssistantInEncryptionCycle();
  477. }
  478. ////////////////////////////////////////////////////////////////////////////
  479. DWORD
  480. EncryptLock()
  481. /*++
  482. Routine Description:
  483. Acquire encryption/decryption routine lock.
  484. Parameters:
  485. None.
  486. Returns:
  487. None.
  488. --*/
  489. {
  490. DWORD dwStatus;
  491. ASSERT( NULL != gm_hMutex );
  492. if( gm_hMutex )
  493. {
  494. dwStatus = WaitForSingleObject( gm_hMutex, INFINITE );
  495. ASSERT( WAIT_FAILED != dwStatus );
  496. }
  497. else
  498. {
  499. dwStatus = ERROR_INTERNAL_ERROR;
  500. }
  501. return dwStatus;
  502. }
  503. void
  504. EncryptUnlock()
  505. /*++
  506. Routine Description:
  507. Release encryption/decryption routine lock.
  508. Parameters:
  509. None.
  510. Returns:
  511. None.
  512. --*/
  513. {
  514. BOOL bSuccess;
  515. bSuccess = ReleaseMutex( gm_hMutex );
  516. ASSERT( TRUE == bSuccess );
  517. }
  518. LPTSTR
  519. GenerateEncryptionPassword()
  520. /*++
  521. Routine Description:
  522. Generate a random password to derive encryption key.
  523. Parameters:
  524. N/A
  525. Returns:
  526. NULL or random password, GetLastError() to
  527. retrieve detail error.
  528. Note:
  529. Use UUID as password to derive encryption key.
  530. --*/
  531. {
  532. RPC_STATUS rpcStatus;
  533. UUID uuid;
  534. LPTSTR pszUuidString = NULL;
  535. rpcStatus = UuidCreate( &uuid );
  536. if( rpcStatus == RPC_S_OK || rpcStatus == RPC_S_UUID_LOCAL_ONLY ||
  537. rpcStatus == RPC_S_UUID_NO_ADDRESS )
  538. {
  539. rpcStatus = UuidToString( &uuid, &pszUuidString );
  540. }
  541. return pszUuidString;
  542. }
  543. BOOL
  544. TSHelpAssistantInEncryptionCycle()
  545. {
  546. LPTSTR pszEncryptKey = NULL;
  547. DWORD cbEncryptKey = 0;
  548. DWORD dwStatus;
  549. dwStatus = EncryptLock();
  550. if( ERROR_SUCCESS == dwStatus )
  551. {
  552. //
  553. // Sessmgr will reset encryption password to NULL
  554. // if there is no help pending
  555. //
  556. dwStatus = RetrieveKeyFromLSA(
  557. SALEMHELPASSISTANTACCOUNT_ENCRYPTIONKEY,
  558. (PBYTE *)&pszEncryptKey,
  559. &cbEncryptKey
  560. );
  561. if( NULL != pszEncryptKey )
  562. {
  563. FreeMemory( pszEncryptKey );
  564. }
  565. EncryptUnlock();
  566. }
  567. return ERROR_SUCCESS == dwStatus;
  568. }
  569. DWORD
  570. TSHelpAssistantBeginEncryptionCycle()
  571. {
  572. DWORD dwStatus;
  573. LPTSTR pszKey = NULL;
  574. DWORD cbKey;
  575. ASSERT( NULL != gm_hMutex );
  576. dwStatus = EncryptLock();
  577. if( ERROR_SUCCESS == dwStatus )
  578. {
  579. //
  580. // Generate a random password for deriving encryption key
  581. //
  582. pszKey = GenerateEncryptionPassword();
  583. if( NULL != pszKey )
  584. {
  585. //
  586. // Store key deriving password into LSA
  587. //
  588. dwStatus = StoreKeyWithLSA(
  589. SALEMHELPASSISTANTACCOUNT_ENCRYPTIONKEY,
  590. (PBYTE)pszKey,
  591. (lstrlenW(pszKey)+1) * sizeof(WCHAR)
  592. );
  593. }
  594. else
  595. {
  596. dwStatus = GetLastError();
  597. }
  598. EncryptUnlock();
  599. }
  600. if( ERROR_SUCCESS == dwStatus )
  601. {
  602. HKEY Handle = NULL;
  603. DWORD dwInHelpMode = 1;
  604. dwStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_CONTROL_TSERVER, 0,
  605. KEY_READ | KEY_SET_VALUE, &Handle );
  606. if ( dwStatus == ERROR_SUCCESS )
  607. {
  608. dwStatus = RegSetValueEx(Handle,REG_MACHINE_IN_HELP_MODE,
  609. 0,REG_DWORD,(const BYTE *)&dwInHelpMode,
  610. sizeof(dwInHelpMode));
  611. }
  612. if(Handle)
  613. {
  614. RegCloseKey(Handle);
  615. }
  616. ASSERT( ERROR_SUCCESS == dwStatus );
  617. }
  618. if( NULL != pszKey )
  619. {
  620. // string is generated by UuidToString()
  621. RpcStringFree( &pszKey );
  622. }
  623. return dwStatus;
  624. }
  625. DWORD
  626. TSHelpAssisantEndEncryptionCycle()
  627. /*++
  628. Routine Description:
  629. End an encryption cycle, a cycle is defined between first help
  630. created in help session manager to last pending help been resolved.
  631. Parameters:
  632. N/A
  633. Returns:
  634. ERROR_SUCCESS or LSA error code
  635. --*/
  636. {
  637. DWORD dwStatus;
  638. ASSERT( NULL != gm_hMutex );
  639. dwStatus = EncryptLock();
  640. if( ERROR_SUCCESS == dwStatus )
  641. {
  642. dwStatus = StoreKeyWithLSA(
  643. SALEMHELPASSISTANTACCOUNT_ENCRYPTIONKEY,
  644. (PBYTE)NULL,
  645. 0
  646. );
  647. EncryptUnlock();
  648. }
  649. if( ERROR_SUCCESS == dwStatus ) // should we not always do it?
  650. {
  651. HKEY Handle = NULL;
  652. DWORD dwInHelpMode = 0;
  653. dwStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_CONTROL_TSERVER, 0,
  654. KEY_READ | KEY_SET_VALUE, &Handle );
  655. if ( dwStatus == ERROR_SUCCESS )
  656. {
  657. dwStatus = RegSetValueEx(Handle,REG_MACHINE_IN_HELP_MODE,
  658. 0,REG_DWORD,(const BYTE *)&dwInHelpMode,
  659. sizeof(dwInHelpMode));
  660. }
  661. if(Handle)
  662. {
  663. RegCloseKey(Handle);
  664. }
  665. ASSERT( ERROR_SUCCESS == dwStatus );
  666. }
  667. return dwStatus;
  668. }
  669. HCRYPTKEY
  670. CreateEncryptDecryptKey(
  671. IN LPCTSTR pszEncryptPrefix,
  672. IN LPCTSTR pszPassword
  673. )
  674. /*++
  675. Routine Description:
  676. CreateEncryptDecryptKey() derive a session encryption/decryption
  677. key from password string.
  678. Parameters:
  679. pszEncryptPrefix : Optional string to be concatenated with password string to derives
  680. an encryption key.
  681. pszPassword : Pointer to password string to derives a session encryption
  682. decryption key.
  683. Returns:
  684. ERROR_SUCCESS or error code.
  685. Note:
  686. Caller must invoke EncryptLock();
  687. --*/
  688. {
  689. DWORD dwStatus = ERROR_SUCCESS;
  690. HCRYPTHASH hCryptHash = NULL;
  691. HCRYPTKEY hCryptKey = NULL;
  692. BOOL bStatus;
  693. LPTSTR pszEncryptKey = NULL;
  694. ASSERT( NULL != pszPassword );
  695. ASSERT( NULL != gm_hCryptProv );
  696. if( NULL != pszPassword && NULL != gm_hCryptProv )
  697. {
  698. if( pszEncryptPrefix )
  699. {
  700. pszEncryptKey = (LPTSTR)AllocMemory( (lstrlen(pszEncryptPrefix) + lstrlen(pszPassword) + 1) * sizeof(TCHAR) );
  701. if( NULL == pszEncryptKey )
  702. {
  703. // Out of memory, can't continue.
  704. goto CLEANUPANDEXIT;
  705. }
  706. lstrcpy( pszEncryptKey, pszEncryptPrefix );
  707. lstrcat( pszEncryptKey, pszPassword );
  708. }
  709. //
  710. // Derives a session key for encryption/decryption.
  711. //
  712. bStatus = CryptCreateHash(
  713. gm_hCryptProv,
  714. CALG_MD5,
  715. 0,
  716. 0,
  717. &hCryptHash
  718. );
  719. if( FALSE == bStatus )
  720. {
  721. dwStatus = GetLastError();
  722. ASSERT(FALSE);
  723. goto CLEANUPANDEXIT;
  724. }
  725. if( pszEncryptKey )
  726. {
  727. bStatus = CryptHashData(
  728. hCryptHash,
  729. (BYTE *)pszEncryptKey,
  730. lstrlen(pszEncryptKey) * sizeof(TCHAR),
  731. 0
  732. );
  733. }
  734. else
  735. {
  736. bStatus = CryptHashData(
  737. hCryptHash,
  738. (BYTE *)pszPassword,
  739. lstrlen(pszPassword) * sizeof(TCHAR),
  740. 0
  741. );
  742. }
  743. if( FALSE == bStatus )
  744. {
  745. dwStatus = GetLastError();
  746. ASSERT(FALSE);
  747. goto CLEANUPANDEXIT;
  748. }
  749. //
  750. // derive a session key for encrypt/decrypt
  751. //
  752. bStatus = CryptDeriveKey(
  753. gm_hCryptProv,
  754. ENCRYPT_ALGORITHM,
  755. hCryptHash,
  756. 0,
  757. &hCryptKey
  758. );
  759. if( FALSE == bStatus )
  760. {
  761. dwStatus = GetLastError();
  762. ASSERT(FALSE);
  763. }
  764. }
  765. else
  766. {
  767. SetLastError( dwStatus = ERROR_INVALID_PARAMETER );
  768. }
  769. CLEANUPANDEXIT:
  770. if( NULL != hCryptHash )
  771. {
  772. (void)CryptDestroyHash( hCryptHash );
  773. }
  774. if( NULL != pszEncryptKey )
  775. {
  776. FreeMemory( pszEncryptKey );
  777. }
  778. return hCryptKey;
  779. }
  780. DWORD
  781. EnsureCryptoProviderCreated()
  782. {
  783. BOOL bStatus;
  784. DWORD dwStatus = ERROR_SUCCESS;
  785. dwStatus = EncryptLock();
  786. if( ERROR_SUCCESS == dwStatus )
  787. {
  788. //
  789. // Acquire a global Crypto provider
  790. //
  791. if( NULL == gm_hCryptProv )
  792. {
  793. bStatus = CryptAcquireContext(
  794. &gm_hCryptProv,
  795. HELPASSISTANT_CRYPT_CONTAINER,
  796. MS_DEF_PROV,
  797. PROV_RSA_FULL,
  798. 0
  799. );
  800. if( FALSE == bStatus )
  801. {
  802. // Create a container if not exists.
  803. bStatus = CryptAcquireContext(
  804. &gm_hCryptProv,
  805. HELPASSISTANT_CRYPT_CONTAINER,
  806. MS_DEF_PROV,
  807. PROV_RSA_FULL,
  808. CRYPT_NEWKEYSET
  809. );
  810. if( FALSE == bStatus )
  811. {
  812. dwStatus = GetLastError();
  813. ASSERT(FALSE);
  814. }
  815. }
  816. }
  817. EncryptUnlock();
  818. }
  819. return dwStatus;
  820. }
  821. HCRYPTKEY
  822. GetEncryptionCycleKey(
  823. IN LPCTSTR pszEncryptPrefix
  824. )
  825. /*++
  826. Routine Description:
  827. Create a encryption/decryption key for current encryption
  828. cycle, function first load password to derive session encryption
  829. key from LSA and invoke CryptAPI to create the session encryption
  830. key. If password is not in LSA, function return error.
  831. Parameters:
  832. None.
  833. Returns:
  834. Handle to session encryption key, NULL if error, use GetLastError to
  835. to retrieve detail error code.
  836. Note:
  837. Caller must invoke EncryptLock();
  838. --*/
  839. {
  840. LPTSTR pszEncryptKey;
  841. DWORD cbEncryptKey;
  842. DWORD dwStatus;
  843. HCRYPTKEY hCryptKey = NULL;
  844. //
  845. // Load password to derive session encryption key from LSA
  846. //
  847. dwStatus = RetrieveKeyFromLSA(
  848. SALEMHELPASSISTANTACCOUNT_ENCRYPTIONKEY,
  849. (PBYTE *)&pszEncryptKey,
  850. &cbEncryptKey
  851. );
  852. if( ERROR_SUCCESS == dwStatus )
  853. {
  854. //
  855. // Make sure global crypto provider exists.
  856. //
  857. dwStatus = EnsureCryptoProviderCreated();
  858. if( ERROR_SUCCESS == dwStatus )
  859. {
  860. //
  861. // Create the session encryption key.
  862. //
  863. hCryptKey = CreateEncryptDecryptKey( pszEncryptPrefix, pszEncryptKey );
  864. }
  865. FreeMemory( pszEncryptKey );
  866. }
  867. return hCryptKey;
  868. }
  869. VOID
  870. TSHelpAssistantEndEncryptionLib()
  871. {
  872. //
  873. // ignore error code, this is only for shutdown
  874. //
  875. if( NULL != gm_hCryptProv )
  876. {
  877. CryptReleaseContext( gm_hCryptProv, 0 );
  878. gm_hCryptProv = NULL;
  879. }
  880. if( NULL != gm_hMutex )
  881. {
  882. ReleaseMutex( gm_hMutex );
  883. }
  884. return;
  885. }
  886. DWORD
  887. TSHelpAssistantInitializeEncryptionLib()
  888. /*++
  889. Routine Description:
  890. Initialize encryption/decryption library
  891. Parameters:
  892. None.
  893. Returns:
  894. ERROR_SUCCESS or error code.
  895. --*/
  896. {
  897. DWORD dwStatus = ERROR_SUCCESS;
  898. BOOL bStatus;
  899. LPTSTR pszEncryptKey;
  900. DWORD cbEncryptKey;
  901. ASSERT( NULL == gm_hCryptProv );
  902. ASSERT( NULL == gm_hMutex );
  903. //
  904. // Create a global mutex
  905. //
  906. gm_hMutex = CreateMutex(
  907. NULL,
  908. FALSE,
  909. SALEMHELPASSISTANTACCOUNT_ENCRYPTMUTEX
  910. );
  911. if( NULL == gm_hMutex )
  912. {
  913. dwStatus = GetLastError();
  914. ASSERT( NULL != gm_hMutex );
  915. }
  916. return dwStatus;
  917. }
  918. DWORD
  919. TSHelpAssistantEncryptData(
  920. IN LPCWSTR pszEncryptPrefixKey,
  921. IN OUT PBYTE pbData,
  922. IN OUT DWORD* pcbData
  923. )
  924. /*++
  925. Routine Description:
  926. Encrypt binary data, called must have invoked
  927. TSHelpAssistantInitializeEncryptionLib() and
  928. TSHelpAssistantBeginEncryptionCycle().
  929. Parameters:
  930. pbData : Pointer to binary data to be encrypted.
  931. pcbData : Size of binary data to be encrypted.
  932. Returns:
  933. ERROR_SUCCESS or error code.
  934. Note:
  935. Caller need to free ppbEncryptedData via LocalFree().
  936. --*/
  937. {
  938. DWORD dwStatus = ERROR_SUCCESS;
  939. BOOL bStatus;
  940. HCRYPTKEY hCryptKey = NULL;
  941. EXCEPTION_RECORD ExceptionCode;
  942. DWORD cbBufSize = *pcbData;
  943. dwStatus = EncryptLock();
  944. if( ERROR_SUCCESS == dwStatus )
  945. {
  946. //
  947. // Retrieve current cycle encryption key
  948. //
  949. hCryptKey = GetEncryptionCycleKey(pszEncryptPrefixKey);
  950. if( NULL == hCryptKey )
  951. {
  952. dwStatus = GetLastError();
  953. EncryptUnlock();
  954. goto CLEANUPANDEXIT;
  955. }
  956. //
  957. // Encrypt the data, not thread safe.
  958. //
  959. __try{
  960. // Stream cipher - same buffer size
  961. bStatus = CryptEncrypt(
  962. hCryptKey,
  963. NULL,
  964. TRUE,
  965. 0,
  966. pbData, // buffer to be encrypted
  967. pcbData, // buffer size
  968. cbBufSize // number of byte to be encrypt
  969. );
  970. if( FALSE == bStatus )
  971. {
  972. dwStatus = GetLastError();
  973. }
  974. }
  975. __except(
  976. ExceptionCode = *(GetExceptionInformation())->ExceptionRecord,
  977. EXCEPTION_EXECUTE_HANDLER )
  978. {
  979. bStatus = FALSE;
  980. dwStatus = ExceptionCode.ExceptionCode;
  981. }
  982. EncryptUnlock();
  983. //
  984. // Using stream cipher, has to be same size.
  985. //
  986. ASSERT( cbBufSize == *pcbData );
  987. }
  988. CLEANUPANDEXIT:
  989. if( NULL != hCryptKey )
  990. {
  991. CryptDestroyKey( hCryptKey );
  992. }
  993. return dwStatus;
  994. }
  995. DWORD
  996. TSHelpAssistantDecryptData(
  997. IN LPCWSTR pszEncryptPrefixKey,
  998. IN OUT PBYTE pbData,
  999. IN OUT DWORD* pcbData
  1000. )
  1001. /*++
  1002. Routine Description:
  1003. Decrypt data previously encrypted using TSHelpAssistantEncryptBase64EncodeData().
  1004. Parameters:
  1005. pbData : Stream of binary data to be decoded/decrypted.
  1006. pcbData : Size of data in bytes to be decrypted/decoded.
  1007. Returns:
  1008. ERROR_SUCCESS or error code
  1009. --*/
  1010. {
  1011. DWORD dwStatus = ERROR_SUCCESS;
  1012. BOOL bStatus;
  1013. HCRYPTKEY hCryptKey = NULL;
  1014. EXCEPTION_RECORD ExceptionCode;
  1015. DWORD dwBufSize = *pcbData;
  1016. dwStatus = EncryptLock();
  1017. if( ERROR_SUCCESS == dwStatus )
  1018. {
  1019. //
  1020. // Retrieve session encryption key for this encryption cycle.
  1021. //
  1022. hCryptKey = GetEncryptionCycleKey(pszEncryptPrefixKey);
  1023. if( NULL == hCryptKey )
  1024. {
  1025. dwStatus = GetLastError();
  1026. EncryptUnlock();
  1027. goto CLEANUPANDEXIT;
  1028. }
  1029. __try {
  1030. // Stream cipher - same buffer size
  1031. bStatus = CryptDecrypt(
  1032. hCryptKey,
  1033. NULL,
  1034. TRUE,
  1035. 0,
  1036. pbData,
  1037. pcbData
  1038. );
  1039. if( FALSE == bStatus )
  1040. {
  1041. dwStatus = GetLastError();
  1042. }
  1043. }
  1044. __except(
  1045. ExceptionCode = *(GetExceptionInformation())->ExceptionRecord,
  1046. EXCEPTION_EXECUTE_HANDLER )
  1047. {
  1048. bStatus = FALSE;
  1049. dwStatus = ExceptionCode.ExceptionCode;
  1050. }
  1051. EncryptUnlock();
  1052. //
  1053. // Stream cipher, same buffer size
  1054. ASSERT( dwBufSize == *pcbData );
  1055. }
  1056. CLEANUPANDEXIT:
  1057. if( NULL != hCryptKey )
  1058. {
  1059. CryptDestroyKey( hCryptKey );
  1060. }
  1061. return dwStatus;
  1062. }
  1063. BOOL
  1064. TSIsMachinePolicyAllowHelp()
  1065. /*++
  1066. Routine Description:
  1067. Check if 'GetHelp' is enabled on local machine, routine first query
  1068. system policy registry key, if policy is not set, then read salem
  1069. specific registry. Default to 'enable' is registry value does not
  1070. exist.
  1071. Parameters:
  1072. None.
  1073. Returns:
  1074. TRUE/FALSE
  1075. --*/
  1076. {
  1077. return RegIsMachinePolicyAllowHelp();
  1078. }
  1079. BOOL
  1080. TSIsMachineInSystemRestore()
  1081. /*+=
  1082. Routine Description:
  1083. Check if our special reg. value exist that indicate system restore
  1084. has rebooted machine.
  1085. Parameters:
  1086. None.
  1087. Returns:
  1088. TRUE/FALSE
  1089. --*/
  1090. {
  1091. DWORD dwStatus;
  1092. HKEY hKey = NULL;
  1093. DWORD cbData;
  1094. DWORD value;
  1095. DWORD type;
  1096. BOOL bInSystemRestore = FALSE;
  1097. dwStatus = RegOpenKeyEx(
  1098. HKEY_LOCAL_MACHINE,
  1099. REG_CONTROL_REMDSK L"\\" REG_CONTROL_HELPSESSIONENTRY,
  1100. 0,
  1101. KEY_ALL_ACCESS,
  1102. &hKey
  1103. );
  1104. if( ERROR_SUCCESS != dwStatus )
  1105. {
  1106. goto CLEANUPANDEXIT;
  1107. }
  1108. cbData = sizeof(value);
  1109. value = 0;
  1110. dwStatus = RegQueryValueEx(
  1111. hKey,
  1112. REG_VALUE_SYSTEMRESTORE,
  1113. 0,
  1114. &type,
  1115. (LPBYTE)&value,
  1116. &cbData
  1117. );
  1118. if( ERROR_SUCCESS == dwStatus && type == REG_DWORD && value == 1 )
  1119. {
  1120. bInSystemRestore = TRUE;
  1121. }
  1122. CLEANUPANDEXIT:
  1123. if( NULL != hKey )
  1124. {
  1125. RegCloseKey(hKey);
  1126. }
  1127. return bInSystemRestore;
  1128. }
  1129. DWORD
  1130. TSSystemRestoreCacheValues()
  1131. /*++
  1132. Routine Description:
  1133. Cache necessary LSA data that we use in Salem for system restore.
  1134. Parameters:
  1135. None.
  1136. Returns:
  1137. ERROR_SUCCESS or error code.
  1138. Note:
  1139. We can't cache HelpAssistant account SID as
  1140. 1) System restore will restore all user account.
  1141. 2) System restore also restore our LSA SID key.
  1142. since our account is created at setup time, account has to
  1143. match SID we cached.
  1144. --*/
  1145. {
  1146. DWORD dwStatus;
  1147. DWORD dwSize;
  1148. DWORD dwValue;
  1149. PBYTE pbData = NULL;
  1150. HKEY hCacheKey = NULL;
  1151. HKEY hRegControlKey = NULL;
  1152. DWORD dwType;
  1153. //
  1154. // Check if we just start up after rebooted from system restore.
  1155. //
  1156. dwStatus = RegOpenKeyEx(
  1157. HKEY_LOCAL_MACHINE,
  1158. REG_CONTROL_REMDSK L"\\" REG_CONTROL_HELPSESSIONENTRY,
  1159. 0,
  1160. KEY_ALL_ACCESS,
  1161. &hCacheKey
  1162. );
  1163. if( ERROR_SUCCESS != dwStatus )
  1164. {
  1165. // This registry key is created at setup time so must exist.
  1166. ASSERT(FALSE);
  1167. dwStatus = ERROR_INTERNAL_ERROR;
  1168. goto CLEANUPANDEXIT;
  1169. }
  1170. //
  1171. // Mark that we are in system restore.
  1172. //
  1173. dwSize = sizeof(dwValue);
  1174. dwValue = 1;
  1175. dwStatus = RegSetValueEx(
  1176. hCacheKey,
  1177. REG_VALUE_SYSTEMRESTORE,
  1178. 0,
  1179. REG_DWORD,
  1180. (LPBYTE)&dwValue,
  1181. dwSize
  1182. );
  1183. //
  1184. // Cache encryption cycle key.
  1185. //
  1186. dwStatus = TSGetEncryptionKey( &pbData, &dwSize );
  1187. if( ERROR_SUCCESS != dwStatus )
  1188. {
  1189. goto CLEANUPANDEXIT;
  1190. }
  1191. dwStatus = RegSetValueEx(
  1192. hCacheKey,
  1193. REG_VALUE_SYSTEMRESTORE_ENCRYPTIONKEY,
  1194. 0,
  1195. REG_BINARY,
  1196. pbData,
  1197. dwSize
  1198. );
  1199. //
  1200. // Cache fAllowToGetHelp
  1201. //
  1202. dwStatus = RegOpenKeyEx(
  1203. HKEY_LOCAL_MACHINE,
  1204. REG_CONTROL_TSERVER,
  1205. 0,
  1206. KEY_READ,
  1207. &hRegControlKey
  1208. );
  1209. if( ERROR_SUCCESS != dwStatus )
  1210. {
  1211. goto CLEANUPANDEXIT;
  1212. }
  1213. dwSize = sizeof(dwValue);
  1214. dwValue = 0;
  1215. dwType = 0;
  1216. dwStatus = RegQueryValueEx(
  1217. hRegControlKey,
  1218. POLICY_TS_REMDSK_ALLOWTOGETHELP,
  1219. 0,
  1220. &dwType,
  1221. (PBYTE)&dwValue,
  1222. &dwSize
  1223. );
  1224. // Key does not exist, assume no help is allow.
  1225. if( ERROR_SUCCESS != dwStatus || dwType != REG_DWORD )
  1226. {
  1227. dwValue = 0;
  1228. }
  1229. dwStatus = RegSetValueEx(
  1230. hCacheKey,
  1231. REG_VALUE_SYSTEMRESTORE_ALLOWTOGETHELP,
  1232. 0,
  1233. REG_DWORD,
  1234. (PBYTE)&dwValue,
  1235. dwSize
  1236. );
  1237. //
  1238. // Cache fInHelpMode
  1239. //
  1240. dwSize = sizeof(dwValue);
  1241. dwValue = 0;
  1242. dwType = 0;
  1243. dwStatus = RegQueryValueEx(
  1244. hRegControlKey,
  1245. REG_MACHINE_IN_HELP_MODE,
  1246. 0,
  1247. &dwType,
  1248. (PBYTE)&dwValue,
  1249. &dwSize
  1250. );
  1251. // Key does not exist, assume No help
  1252. if( ERROR_SUCCESS != dwStatus || dwType != REG_DWORD )
  1253. {
  1254. dwValue = 0;
  1255. }
  1256. dwStatus = RegSetValueEx(
  1257. hCacheKey,
  1258. REG_VALUE_SYSTEMRESTORE_INHELPMODE,
  1259. 0,
  1260. REG_DWORD,
  1261. (PBYTE)&dwValue,
  1262. dwSize
  1263. );
  1264. CLEANUPANDEXIT:
  1265. if( NULL != hCacheKey )
  1266. {
  1267. RegCloseKey( hCacheKey );
  1268. }
  1269. if( NULL != hRegControlKey )
  1270. {
  1271. RegCloseKey( hRegControlKey );
  1272. }
  1273. if( NULL != pbData )
  1274. {
  1275. LocalFree( pbData );
  1276. }
  1277. return dwStatus;
  1278. }
  1279. DWORD
  1280. TSSystemRestoreResetValues()
  1281. /*++
  1282. Routine Description:
  1283. Reset necessary LSA data that we use in Salem for system restore.
  1284. Parameters:
  1285. None.
  1286. Returns:
  1287. ERROR_SUCCESS or error code.
  1288. --*/
  1289. {
  1290. DWORD dwStatus;
  1291. PBYTE pbData = NULL;
  1292. DWORD dwSize;
  1293. DWORD dwType;
  1294. DWORD dwValue;
  1295. HKEY hRegControlKey = NULL;
  1296. HKEY hCacheKey = NULL;
  1297. //
  1298. // Check if we just start up after rebooted from system restore.
  1299. //
  1300. dwStatus = RegOpenKeyEx(
  1301. HKEY_LOCAL_MACHINE,
  1302. REG_CONTROL_REMDSK L"\\" REG_CONTROL_HELPSESSIONENTRY,
  1303. 0,
  1304. KEY_ALL_ACCESS,
  1305. &hCacheKey
  1306. );
  1307. if( ERROR_SUCCESS != dwStatus )
  1308. {
  1309. // This registry key is created at setup time so must exist.
  1310. ASSERT(FALSE);
  1311. dwStatus = ERROR_INTERNAL_ERROR;
  1312. goto CLEANUPANDEXIT;
  1313. }
  1314. //
  1315. // Restore necessary LSA values.
  1316. //
  1317. dwSize = 0;
  1318. dwStatus = RegQueryValueEx(
  1319. hCacheKey,
  1320. REG_VALUE_SYSTEMRESTORE_ENCRYPTIONKEY,
  1321. 0,
  1322. &dwType,
  1323. NULL,
  1324. &dwSize
  1325. );
  1326. if( ERROR_SUCCESS != dwStatus || dwType != REG_BINARY )
  1327. {
  1328. goto CLEANUPANDEXIT;
  1329. }
  1330. pbData = (PBYTE) LocalAlloc( LPTR, dwSize );
  1331. if( NULL == pbData )
  1332. {
  1333. dwStatus = GetLastError();
  1334. goto CLEANUPANDEXIT;
  1335. }
  1336. // Restore encryption key
  1337. dwStatus = RegQueryValueEx(
  1338. hCacheKey,
  1339. REG_VALUE_SYSTEMRESTORE_ENCRYPTIONKEY,
  1340. 0,
  1341. &dwType,
  1342. pbData,
  1343. &dwSize
  1344. );
  1345. if( ERROR_SUCCESS != dwStatus )
  1346. {
  1347. goto CLEANUPANDEXIT;
  1348. }
  1349. dwStatus = TSSetEncryptionKey(pbData, dwSize);
  1350. //
  1351. // Reset fAllowToGetHelp
  1352. //
  1353. dwStatus = RegOpenKeyEx(
  1354. HKEY_LOCAL_MACHINE,
  1355. REG_CONTROL_TSERVER,
  1356. 0,
  1357. KEY_READ | KEY_SET_VALUE,
  1358. &hRegControlKey
  1359. );
  1360. if( ERROR_SUCCESS != dwStatus )
  1361. {
  1362. goto CLEANUPANDEXIT;
  1363. }
  1364. dwSize = sizeof(dwValue);
  1365. dwValue = 0;
  1366. dwType = 0;
  1367. dwStatus = RegQueryValueEx(
  1368. hCacheKey,
  1369. REG_VALUE_SYSTEMRESTORE_ALLOWTOGETHELP,
  1370. 0,
  1371. &dwType,
  1372. (PBYTE)&dwValue,
  1373. &dwSize
  1374. );
  1375. // Key does not exist, assume no help is allow.
  1376. if( ERROR_SUCCESS != dwStatus || dwType != REG_DWORD )
  1377. {
  1378. dwValue = 0;
  1379. }
  1380. dwStatus = RegSetValueEx(
  1381. hRegControlKey,
  1382. POLICY_TS_REMDSK_ALLOWTOGETHELP,
  1383. 0,
  1384. REG_DWORD,
  1385. (PBYTE)&dwValue,
  1386. dwSize
  1387. );
  1388. //
  1389. // Reset fInHelpMode
  1390. //
  1391. dwSize = sizeof(dwValue);
  1392. dwValue = 0;
  1393. dwType = 0;
  1394. dwStatus = RegQueryValueEx(
  1395. hCacheKey,
  1396. REG_VALUE_SYSTEMRESTORE_INHELPMODE,
  1397. 0,
  1398. &dwType,
  1399. (PBYTE)&dwValue,
  1400. &dwSize
  1401. );
  1402. // Key does not exist, assume not in help
  1403. if( ERROR_SUCCESS != dwStatus || dwType != REG_DWORD )
  1404. {
  1405. dwValue = 0;
  1406. }
  1407. dwStatus = RegSetValueEx(
  1408. hRegControlKey,
  1409. REG_MACHINE_IN_HELP_MODE,
  1410. 0,
  1411. REG_DWORD,
  1412. (PBYTE)&dwValue,
  1413. dwSize
  1414. );
  1415. CLEANUPANDEXIT:
  1416. if( NULL != pbData )
  1417. {
  1418. LocalFree(pbData);
  1419. }
  1420. if( NULL != hCacheKey )
  1421. {
  1422. RegDeleteValue( hCacheKey, REG_VALUE_SYSTEMRESTORE_ENCRYPTIONKEY );
  1423. RegDeleteValue( hCacheKey, REG_VALUE_SYSTEMRESTORE );
  1424. RegDeleteValue( hCacheKey, REG_VALUE_SYSTEMRESTORE_ALLOWTOGETHELP );
  1425. RegDeleteValue( hCacheKey, REG_VALUE_SYSTEMRESTORE_INHELPMODE );
  1426. RegCloseKey( hCacheKey );
  1427. }
  1428. if( NULL != hRegControlKey )
  1429. {
  1430. RegCloseKey( hRegControlKey );
  1431. }
  1432. return dwStatus;
  1433. }