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.

1874 lines
47 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. HelpAcc.cpp
  5. Abstract:
  6. Implementation of __HelpAssistantAccount to manage Help Assistant account, this
  7. including creating account, setting various account rights and password.
  8. Author:
  9. HueiWang 06/29/2000
  10. --*/
  11. #include "stdafx.h"
  12. #include "helpacc.h"
  13. #include "resource.h"
  14. #include "policy.h"
  15. #include "cfgbkend.h"
  16. #include "cfgbkend_i.c"
  17. #include "helper.h"
  18. //
  19. // Help account lock
  20. CCriticalSection __HelpAssistantAccount::gm_HelpAccountCS;
  21. // Help Account name and pasword
  22. CComBSTR __HelpAssistantAccount::gm_bstrHelpAccountPwd;
  23. CComBSTR __HelpAssistantAccount::gm_bstrHelpAccountName(HELPASSISTANTACCOUNT_NAME);
  24. // Help Account SID
  25. PBYTE __HelpAssistantAccount::gm_pbHelpAccountSid = NULL;
  26. DWORD __HelpAssistantAccount::gm_cbHelpAccountSid = 0;
  27. DWORD __HelpAssistantAccount::gm_dwAccErrCode = ERROR_INVALID_DATA;
  28. ///////////////////////////////////////////////////////////////////////////
  29. //
  30. //
  31. //
  32. DWORD
  33. GetGUIDString(
  34. OUT LPTSTR* pszString
  35. )
  36. /*++
  37. --*/
  38. {
  39. UUID uuid;
  40. RPC_STATUS rpcStatus;
  41. LPTSTR pszUuid = NULL;
  42. rpcStatus = UuidCreate( &uuid );
  43. if( rpcStatus != RPC_S_OK &&
  44. rpcStatus != RPC_S_UUID_LOCAL_ONLY &&
  45. rpcStatus != RPC_S_UUID_NO_ADDRESS )
  46. {
  47. goto CLEANUPANDEXIT;
  48. }
  49. rpcStatus = UuidToString( &uuid, &pszUuid );
  50. if( RPC_S_OK == rpcStatus )
  51. {
  52. *pszString = (LPTSTR)LocalAlloc( LPTR, (lstrlen(pszUuid)+1)*sizeof(TCHAR));
  53. if( NULL == *pszString )
  54. {
  55. rpcStatus = GetLastError();
  56. }
  57. else
  58. {
  59. lstrcpy( *pszString, pszUuid );
  60. }
  61. }
  62. CLEANUPANDEXIT:
  63. if( NULL != pszUuid )
  64. {
  65. RpcStringFree(&pszUuid);
  66. }
  67. return rpcStatus;
  68. }
  69. DWORD
  70. GenerateUniqueHelpAssistantName(
  71. IN LPCTSTR pszAccNamePrefix,
  72. OUT CComBSTR& bstrAccName
  73. )
  74. /*++
  75. --*/
  76. {
  77. DWORD dwStatus;
  78. LPTSTR pszString;
  79. dwStatus = GetGUIDString( &pszString );
  80. if( ERROR_SUCCESS == dwStatus )
  81. {
  82. DWORD dwLen;
  83. DWORD dwAppendStrLen;
  84. LPTSTR pszAppendStr;
  85. // MAX user account name is 20 chars.
  86. bstrAccName = pszAccNamePrefix;
  87. bstrAccName += L"_";
  88. dwLen = bstrAccName.Length();
  89. dwAppendStrLen = lstrlen(pszString);
  90. if( dwAppendStrLen < MAX_USERNAME_LENGTH - dwLen )
  91. {
  92. pszAppendStr = pszString;
  93. }
  94. else
  95. {
  96. pszAppendStr = pszString + dwAppendStrLen - (MAX_USERNAME_LENGTH - dwLen);
  97. }
  98. bstrAccName += pszAppendStr;
  99. }
  100. return dwStatus;
  101. }
  102. HRESULT
  103. __HelpAssistantAccount::SetupHelpAccountTSSettings()
  104. /*++
  105. Routine Description:
  106. Setup bunch of HelpAssistant account TS settings.
  107. Parameters:
  108. None
  109. Returns:
  110. ERROR_SUCCESS or error code
  111. --*/
  112. {
  113. CComBSTR bstrScript;
  114. DWORD dwStatus;
  115. PBYTE pbAlreadySetup = NULL;
  116. DWORD cbAlreadySetup = 0;
  117. HRESULT hRes = S_OK;
  118. CCriticalSectionLocker l(gm_HelpAccountCS);
  119. dwStatus = RetrieveKeyFromLSA(
  120. HELPACCOUNTPROPERLYSETUP,
  121. (PBYTE *)&pbAlreadySetup,
  122. &cbAlreadySetup
  123. );
  124. if( ERROR_SUCCESS != dwStatus )
  125. {
  126. hRes = GetHelpAccountScript( bstrScript );
  127. if( SUCCEEDED(hRes) )
  128. {
  129. // always config again.
  130. hRes = ConfigHelpAccountTSSettings(
  131. gm_bstrHelpAccountName,
  132. bstrScript
  133. );
  134. if( SUCCEEDED(hRes) )
  135. {
  136. dwStatus = StoreKeyWithLSA(
  137. HELPACCOUNTPROPERLYSETUP,
  138. (PBYTE) &dwStatus,
  139. sizeof(dwStatus)
  140. );
  141. if( ERROR_SUCCESS != dwStatus )
  142. {
  143. hRes = HRESULT_FROM_WIN32(hRes);
  144. }
  145. }
  146. }
  147. }
  148. if( NULL != pbAlreadySetup )
  149. {
  150. LocalFree( pbAlreadySetup );
  151. }
  152. return hRes;
  153. }
  154. HRESULT
  155. __HelpAssistantAccount::LookupHelpAccountSid(
  156. IN LPTSTR pszAccName,
  157. OUT PSID* ppSid,
  158. OUT DWORD* pcbSid
  159. )
  160. /*++
  161. Routine Description:
  162. This routine retrieve help assistant account's SID.
  163. Parameters:
  164. pszAccName : Name of Help Assistant Account.
  165. ppSid : Pointer to PSID to receive account SID.
  166. cbSid : Size of SID return on ppSid
  167. Returns:
  168. S_OK or error code.
  169. --*/
  170. {
  171. DWORD dwStatus = ERROR_SUCCESS;
  172. DWORD cbSid = 0;
  173. DWORD cbDomainName = 0;
  174. PSID pAccSid = NULL;
  175. LPTSTR pszDomainName = NULL;
  176. BOOL bSuccess;
  177. SID_NAME_USE SidUse;
  178. // Get buffer size required for SID
  179. bSuccess = LookupAccountName(
  180. NULL,
  181. pszAccName,
  182. NULL,
  183. &cbSid,
  184. NULL,
  185. &cbDomainName,
  186. &SidUse
  187. );
  188. if( TRUE == bSuccess ||
  189. ERROR_INSUFFICIENT_BUFFER == GetLastError() )
  190. {
  191. pAccSid = (PSID)LocalAlloc( LPTR, cbSid );
  192. if( NULL == pAccSid )
  193. {
  194. dwStatus = GetLastError();
  195. goto CLEANUPANDEXIT;
  196. }
  197. // allocate buffer for domain name so LookupAccountName()
  198. // does not return insufficient buffer
  199. pszDomainName = (LPTSTR)LocalAlloc( LPTR, (cbDomainName + 1) * sizeof(TCHAR) );
  200. if( NULL == pszDomainName )
  201. {
  202. dwStatus = GetLastError();
  203. goto CLEANUPANDEXIT;
  204. }
  205. bSuccess = LookupAccountName(
  206. NULL,
  207. pszAccName,
  208. pAccSid,
  209. &cbSid,
  210. pszDomainName,
  211. &cbDomainName,
  212. &SidUse
  213. );
  214. if( FALSE == bSuccess || SidTypeUser != SidUse )
  215. {
  216. //MYASSERT(FALSE);
  217. dwStatus = E_UNEXPECTED;
  218. goto CLEANUPANDEXIT;
  219. }
  220. // Make sure we gets valid SID
  221. bSuccess = IsValidSid( pAccSid );
  222. if( FALSE == bSuccess )
  223. {
  224. dwStatus = E_UNEXPECTED;
  225. }
  226. }
  227. else
  228. {
  229. dwStatus = GetLastError();
  230. }
  231. CLEANUPANDEXIT:
  232. if( dwStatus == ERROR_SUCCESS )
  233. {
  234. *ppSid = pAccSid;
  235. *pcbSid = cbSid;
  236. }
  237. else
  238. {
  239. if( NULL != pAccSid )
  240. {
  241. LocalFree( pAccSid );
  242. }
  243. }
  244. if( NULL != pszDomainName )
  245. {
  246. LocalFree( pszDomainName );
  247. }
  248. return HRESULT_FROM_WIN32(dwStatus);
  249. }
  250. HRESULT
  251. __HelpAssistantAccount::CacheHelpAccountSID()
  252. /*++
  253. Routine Description:
  254. This routine retrieve help assistant account's SID and store
  255. it with LSA, this is so that PTS can verify login user is
  256. the actual Salem Help Assistant Account.
  257. Parameters:
  258. None.
  259. Returns:
  260. S_OK
  261. --*/
  262. {
  263. DWORD dwStatus = ERROR_SUCCESS;
  264. DWORD cbSid = 0;
  265. PSID pAccSid = NULL;
  266. dwStatus = LookupHelpAccountSid(
  267. gm_bstrHelpAccountName,
  268. &pAccSid,
  269. &cbSid
  270. );
  271. if( ERROR_SUCCESS == dwStatus )
  272. {
  273. // Store this with LSA
  274. dwStatus = StoreKeyWithLSA(
  275. HELPASSISTANTACCOUNT_SIDKEY,
  276. (PBYTE)pAccSid,
  277. cbSid
  278. );
  279. }
  280. if( NULL != pAccSid )
  281. {
  282. LocalFree( pAccSid );
  283. }
  284. return HRESULT_FROM_WIN32(dwStatus);
  285. }
  286. HRESULT
  287. __HelpAssistantAccount::GetHelpAccountScript(
  288. OUT CComBSTR& bstrScript
  289. )
  290. /*++
  291. Routine Description:
  292. Routine to retrieve logon script for help assistant account.
  293. Parameters:
  294. bstrScript : Reference to CComBSTR, on return, this parameter contains
  295. full path to the logon script.
  296. Returns:
  297. ERROR_SUCCESS or error code from GetSystemDirectory
  298. NOTE:
  299. TODO - Need to get the actual path/name.
  300. --*/
  301. {
  302. DWORD dwStatus = ERROR_SUCCESS;
  303. TCHAR szScript[MAX_PATH + 1];
  304. dwStatus = (DWORD)GetSystemDirectory( szScript, MAX_PATH );
  305. if( 0 == dwStatus )
  306. {
  307. //MYASSERT(FALSE);
  308. dwStatus = GetLastError();
  309. }
  310. else
  311. {
  312. bstrScript = szScript;
  313. bstrScript += _TEXT("\\");
  314. bstrScript += RDSADDINEXECNAME;
  315. dwStatus = ERROR_SUCCESS;
  316. }
  317. return HRESULT_FROM_WIN32(dwStatus);
  318. }
  319. HRESULT
  320. __HelpAssistantAccount::Initialize(
  321. BOOL bVerifyPassword /* = TRUE */
  322. )
  323. /*++
  324. Routine Description:
  325. Initialize HelpAssistantAccount structure global variables.
  326. Parameters:
  327. None.
  328. Returns:
  329. S_OK or error code.
  330. --*/
  331. {
  332. HRESULT hRes = S_OK;
  333. LPTSTR pszOldPassword = NULL;
  334. DWORD cbOldPassword = 0;
  335. DWORD dwStatus;
  336. BOOL bStatus;
  337. TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH+2];
  338. DWORD cbComputerName = MAX_COMPUTERNAME_LENGTH+1;
  339. PSID pCachedHelpAccSid = NULL;
  340. DWORD cbCachedHelpAccSid = 0;
  341. BOOL bAccountEnable = TRUE;
  342. LPTSTR rights[1];
  343. LPTSTR pszHelpAcctName = NULL;
  344. LPTSTR pszHelpAcctDomainName = NULL;
  345. CCriticalSectionLocker l(gm_HelpAccountCS);
  346. if( FALSE == GetComputerName( szComputerName, &cbComputerName ) )
  347. {
  348. //MYASSERT(FALSE);
  349. gm_dwAccErrCode = GetLastError();
  350. goto CLEANUPANDEXIT;
  351. }
  352. //
  353. // Load password from LSA
  354. //
  355. dwStatus = RetrieveKeyFromLSA(
  356. HELPASSISTANTACCOUNT_PASSWORDKEY,
  357. (PBYTE *)&pszOldPassword,
  358. &cbOldPassword
  359. );
  360. if( ERROR_SUCCESS != dwStatus )
  361. {
  362. //
  363. // Account is not properly setup
  364. gm_dwAccErrCode = dwStatus;
  365. goto CLEANUPANDEXIT;
  366. }
  367. // Load account SID
  368. dwStatus = RetrieveKeyFromLSA(
  369. HELPASSISTANTACCOUNT_SIDKEY,
  370. (PBYTE *)&pCachedHelpAccSid,
  371. &cbCachedHelpAccSid
  372. );
  373. if( ERROR_SUCCESS != dwStatus )
  374. {
  375. gm_dwAccErrCode = dwStatus;
  376. goto CLEANUPANDEXIT;
  377. }
  378. dwStatus = TSGetHelpAssistantAccountName( &pszHelpAcctDomainName, &pszHelpAcctName );
  379. if( ERROR_SUCCESS != dwStatus )
  380. {
  381. gm_dwAccErrCode = dwStatus;
  382. goto CLEANUPANDEXIT;
  383. }
  384. gm_bstrHelpAccountName = pszHelpAcctName;
  385. DebugPrintf(
  386. _TEXT("HelpAssistant account name : %s\n"),
  387. gm_bstrHelpAccountName
  388. );
  389. //
  390. // Check if account is enable, if not enable it or
  391. // LogonUser() will failed with error 1331
  392. //
  393. dwStatus = IsLocalAccountEnabled(
  394. gm_bstrHelpAccountName,
  395. &bAccountEnable
  396. );
  397. if( ERROR_SUCCESS != dwStatus )
  398. {
  399. // critical error, account might not exist.
  400. gm_dwAccErrCode = ERROR_INVALID_DATA;
  401. goto CLEANUPANDEXIT;
  402. }
  403. //
  404. // Everything is OK, cache values.
  405. //
  406. gm_bstrHelpAccountPwd = pszOldPassword;
  407. gm_pbHelpAccountSid = (PBYTE)pCachedHelpAccSid;
  408. gm_cbHelpAccountSid = cbCachedHelpAccSid;
  409. pCachedHelpAccSid = NULL;
  410. //
  411. // Setup/upgrade on DC will try to validate password but
  412. // since account on DC goes to ADS, server might not be
  413. // available, we will reset password on start up so we don't
  414. // need to validate password on upgrade.
  415. //
  416. if( TRUE == bVerifyPassword )
  417. {
  418. if( FALSE == bAccountEnable )
  419. {
  420. // enable the account so we can check password
  421. dwStatus = EnableHelpAssistantAccount( TRUE );
  422. if( ERROR_SUCCESS != dwStatus )
  423. {
  424. //
  425. // Can't enable the account, critical error
  426. //
  427. gm_dwAccErrCode = dwStatus;
  428. goto CLEANUPANDEXIT;
  429. }
  430. }
  431. rights[0] = SE_NETWORK_LOGON_NAME;
  432. //
  433. // Enable network logon rights to validate password
  434. //
  435. dwStatus = EnableAccountRights(
  436. TRUE,
  437. 1,
  438. rights
  439. );
  440. if( ERROR_SUCCESS != dwStatus )
  441. {
  442. DebugPrintf(
  443. _TEXT("EnableAccountRights() returns 0x%08x\n"),
  444. dwStatus
  445. );
  446. gm_dwAccErrCode = dwStatus;
  447. //
  448. // Error code path, restore account status
  449. //
  450. if( FALSE == bAccountEnable )
  451. {
  452. // non-critical error.
  453. EnableHelpAssistantAccount( bAccountEnable );
  454. }
  455. goto CLEANUPANDEXIT;
  456. }
  457. // valid password
  458. bStatus = ValidatePassword(
  459. gm_bstrHelpAccountName,
  460. L".",
  461. pszOldPassword
  462. );
  463. if( FALSE == bStatus )
  464. {
  465. // mismatch password, force password change
  466. dwStatus = ChangeLocalAccountPassword(
  467. gm_bstrHelpAccountName,
  468. pszOldPassword,
  469. pszOldPassword
  470. );
  471. DebugPrintf(
  472. _TEXT("ChangeLocalAccountPassword() returns %d\n"),
  473. dwStatus
  474. );
  475. if( ERROR_SUCCESS != dwStatus )
  476. {
  477. gm_dwAccErrCode = ERROR_LOGON_FAILURE;
  478. }
  479. else
  480. {
  481. bStatus = ValidatePassword(
  482. gm_bstrHelpAccountName,
  483. L".",
  484. pszOldPassword
  485. );
  486. }
  487. }
  488. //
  489. // Disable network interactive rights
  490. //
  491. dwStatus = EnableAccountRights(
  492. FALSE,
  493. 1,
  494. rights
  495. );
  496. MYASSERT( ERROR_SUCCESS == dwStatus );
  497. //
  498. // Restore account status
  499. //
  500. if( FALSE == bAccountEnable )
  501. {
  502. // non-critical error.
  503. EnableHelpAssistantAccount( bAccountEnable );
  504. }
  505. }
  506. //
  507. // No checking on dwStatus from disabling account rights,
  508. // security risk but not affecting our operation
  509. //
  510. gm_dwAccErrCode = dwStatus;
  511. CLEANUPANDEXIT:
  512. FreeMemory(pszHelpAcctDomainName);
  513. FreeMemory(pszHelpAcctName);
  514. FreeMemory( pszOldPassword );
  515. FreeMemory( pCachedHelpAccSid );
  516. return HRESULT_FROM_WIN32( gm_dwAccErrCode );
  517. }
  518. HRESULT
  519. __HelpAssistantAccount::DeleteHelpAccount()
  520. /*++
  521. Routine Description:
  522. Delete Help Assistant Account.
  523. Parameters:
  524. None.
  525. Returns:
  526. S_OK or error code.
  527. --*/
  528. {
  529. DWORD dwStatus;
  530. BOOL bStatus;
  531. BOOL bEnable;
  532. CCriticalSectionLocker l(gm_HelpAccountCS);
  533. if( ERROR_SUCCESS == IsLocalAccountEnabled(gm_bstrHelpAccountName, &bEnable) )
  534. {
  535. //
  536. // remove all TS rights or it will shows up
  537. // as unknown SID string on TSCC permission page
  538. //
  539. SetupHelpAccountTSRights(
  540. TRUE,
  541. FALSE,
  542. FALSE,
  543. WINSTATION_ALL_ACCESS
  544. );
  545. // don't need to verify password
  546. (void) Initialize(FALSE);
  547. // Always delete interactive right or there will
  548. // be lots of entries in local security
  549. (void) EnableRemoteInteractiveRight(FALSE);
  550. }
  551. //
  552. // Delete NT account
  553. //
  554. dwStatus = NetUserDel(
  555. NULL,
  556. gm_bstrHelpAccountName
  557. );
  558. if( ERROR_ACCESS_DENIED == dwStatus )
  559. {
  560. // We don't have priviledge, probably can't
  561. // touch accunt, get out.
  562. // MYASSERT(FALSE);
  563. goto CLEANUPANDEXIT;
  564. }
  565. dwStatus = ERROR_SUCCESS;
  566. //
  567. // Overwrite password stored with LSA
  568. //
  569. StoreKeyWithLSA(
  570. HELPASSISTANTACCOUNT_PASSWORDKEY,
  571. NULL,
  572. 0
  573. );
  574. //
  575. // Overwrite Help Assistant Account SID store in LSA
  576. //
  577. StoreKeyWithLSA(
  578. HELPASSISTANTACCOUNT_SIDKEY,
  579. NULL,
  580. 0
  581. );
  582. // Not yet setup Help Assistant account
  583. StoreKeyWithLSA(
  584. HELPACCOUNTPROPERLYSETUP,
  585. NULL,
  586. 0
  587. );
  588. CLEANUPANDEXIT:
  589. return HRESULT_FROM_WIN32(dwStatus);
  590. }
  591. HRESULT
  592. __HelpAssistantAccount::CreateHelpAccount(
  593. IN LPCTSTR pszPassword
  594. )
  595. /*++
  596. Routine Description:
  597. Create Help Assistant Account.
  598. Parameters:
  599. pszPassword : Suggested password.
  600. Returns:
  601. S_OK or error code.
  602. Note:
  603. 1) Routine should only be invoked during setup.
  604. 2) Password parameter might not be honor in future so
  605. it is only a suggestion.
  606. --*/
  607. {
  608. HRESULT hRes = S_OK;
  609. BOOL bStatus;
  610. DWORD dwStatus;
  611. CComBSTR AccFullName;
  612. CComBSTR AccDesc;
  613. CComBSTR AccName;
  614. CComBSTR bstrNewHelpAccName;
  615. TCHAR newAssistantAccountPwd[MAX_HELPACCOUNT_PASSWORD + 1];
  616. CComBSTR bstrScript;
  617. BOOL bPersonalOrProMachine;
  618. CCriticalSectionLocker l(gm_HelpAccountCS);
  619. bStatus = AccName.LoadString(IDS_HELPACCNAME);
  620. if( FALSE == bStatus )
  621. {
  622. hRes = E_UNEXPECTED;
  623. return hRes;
  624. }
  625. bStatus = AccFullName.LoadString(
  626. IDS_HELPACCFULLNAME
  627. );
  628. if( FALSE == bStatus )
  629. {
  630. hRes = E_UNEXPECTED;
  631. return hRes;
  632. }
  633. bStatus = AccDesc.LoadString(
  634. IDS_HELPACCDESC
  635. );
  636. if( FALSE == bStatus )
  637. {
  638. hRes = E_UNEXPECTED;
  639. return hRes;
  640. }
  641. bPersonalOrProMachine = IsPersonalOrProMachine();
  642. //
  643. // Verify help assistant account exist and don't check
  644. // password, on service startup, we will verify password
  645. // if mismatch, service startup will reset the password.
  646. //
  647. hRes = Initialize( FALSE );
  648. if( SUCCEEDED(hRes) )
  649. {
  650. // Account already exists, check if this is the hardcoded HelpAssistant,
  651. // if so, rename to whatever in resource, we only need to rename
  652. // account if
  653. // 1) existing account is HelpAssistant - administrator has not rename it.
  654. // 2) account name in resource is not HelpAssistant.
  655. // 3) We are running on server or above SKU.
  656. if( (FALSE == bPersonalOrProMachine) ||
  657. (gm_bstrHelpAccountName == HELPASSISTANTACCOUNT_NAME &&
  658. AccName != HELPASSISTANTACCOUNT_NAME) )
  659. {
  660. if( FALSE == bPersonalOrProMachine )
  661. {
  662. // on server or above SKU, we rename it to unique name.
  663. dwStatus = GenerateUniqueHelpAssistantName( AccName, bstrNewHelpAccName );
  664. }
  665. else
  666. {
  667. dwStatus = ERROR_SUCCESS;
  668. bstrNewHelpAccName = AccName;
  669. }
  670. if( ERROR_SUCCESS == dwStatus )
  671. {
  672. dwStatus = RenameLocalAccount( gm_bstrHelpAccountName, bstrNewHelpAccName );
  673. }
  674. if( ERROR_SUCCESS == dwStatus )
  675. {
  676. // cache the new help assistant account name.
  677. gm_bstrHelpAccountName = bstrNewHelpAccName;
  678. }
  679. else
  680. {
  681. // force a delete and reload.
  682. hRes = HRESULT_FROM_WIN32( dwStatus );
  683. }
  684. }
  685. //
  686. // Account already exist, change the description,
  687. // if failed, force delete and re-create account again
  688. //
  689. if( SUCCEEDED(hRes) )
  690. {
  691. //
  692. // Update account description
  693. //
  694. dwStatus = UpdateLocalAccountFullnameAndDesc(
  695. gm_bstrHelpAccountName,
  696. AccFullName,
  697. AccDesc
  698. );
  699. if( ERROR_SUCCESS != dwStatus )
  700. {
  701. hRes = HRESULT_FROM_WIN32(dwStatus);
  702. }
  703. }
  704. }
  705. if( FAILED(hRes) )
  706. {
  707. //
  708. // Either password mismatch or account not exists,...
  709. // delete account and re-create one
  710. //
  711. (void)DeleteHelpAccount();
  712. // generate password if NULL or zero length string
  713. if( NULL == pszPassword || 0 == lstrlen(pszPassword) )
  714. {
  715. dwStatus = CreatePassword(newAssistantAccountPwd);
  716. if( ERROR_SUCCESS != dwStatus )
  717. {
  718. hRes = HRESULT_FROM_WIN32(dwStatus);
  719. goto CLEANUPANDEXIT;
  720. }
  721. }
  722. else
  723. {
  724. memset(
  725. newAssistantAccountPwd,
  726. 0,
  727. sizeof(newAssistantAccountPwd)
  728. );
  729. _tcsncpy(
  730. newAssistantAccountPwd,
  731. pszPassword,
  732. min(lstrlen(pszPassword), MAX_HELPACCOUNT_PASSWORD)
  733. );
  734. }
  735. hRes = GetHelpAccountScript( bstrScript );
  736. if( FAILED(hRes) )
  737. {
  738. goto CLEANUPANDEXIT;
  739. }
  740. //
  741. // On personal or pro machine, we use what's in resorce.
  742. // server or advance server, we use HelpAssist_<Random string>
  743. //
  744. if( FALSE == bPersonalOrProMachine )
  745. {
  746. dwStatus = GenerateUniqueHelpAssistantName(
  747. AccName,
  748. gm_bstrHelpAccountName
  749. );
  750. if( ERROR_SUCCESS != dwStatus )
  751. {
  752. hRes = HRESULT_FROM_WIN32(dwStatus);
  753. goto CLEANUPANDEXIT;
  754. }
  755. }
  756. else
  757. {
  758. gm_bstrHelpAccountName = AccName;
  759. }
  760. if( SUCCEEDED(hRes) )
  761. {
  762. BOOL bAccExist;
  763. //
  764. // Create local account will enables it if account is disabled
  765. //
  766. dwStatus = CreateLocalAccount(
  767. gm_bstrHelpAccountName,
  768. newAssistantAccountPwd,
  769. AccFullName,
  770. AccDesc,
  771. NULL,
  772. bstrScript,
  773. &bAccExist
  774. );
  775. if( ERROR_SUCCESS == dwStatus )
  776. {
  777. if( FALSE == bAccExist )
  778. {
  779. DebugPrintf( _TEXT("%s account is new\n"), gm_bstrHelpAccountName );
  780. //
  781. // Store the actual Help Assistant Account's SID with LSA
  782. // so TermSrv can verify this SID
  783. //
  784. hRes = CacheHelpAccountSID();
  785. }
  786. else
  787. {
  788. DebugPrintf( _TEXT("%s account exists\n") );
  789. hRes = ResetHelpAccountPassword(newAssistantAccountPwd);
  790. }
  791. if( SUCCEEDED(hRes) )
  792. {
  793. dwStatus = StoreKeyWithLSA(
  794. HELPASSISTANTACCOUNT_PASSWORDKEY,
  795. (PBYTE)newAssistantAccountPwd,
  796. sizeof(newAssistantAccountPwd)
  797. );
  798. hRes = HRESULT_FROM_WIN32( dwStatus );
  799. }
  800. if( SUCCEEDED(hRes) )
  801. {
  802. // reload global variable here, don't need to
  803. // verify password, DC ADS might not be available.
  804. hRes = Initialize( FALSE );
  805. }
  806. //
  807. // TODO - need to fix CreateLocalAccount() on SRV SKU
  808. // too riskly for client release.
  809. //
  810. UpdateLocalAccountFullnameAndDesc(
  811. gm_bstrHelpAccountName,
  812. AccFullName,
  813. AccDesc
  814. );
  815. }
  816. else
  817. {
  818. hRes = HRESULT_FROM_WIN32( dwStatus );
  819. }
  820. }
  821. }
  822. if( SUCCEEDED(hRes) )
  823. {
  824. // remove network and interactive logon rights from account.
  825. LPTSTR rights[1];
  826. DWORD dwStatus;
  827. rights[0] = SE_NETWORK_LOGON_NAME;
  828. dwStatus = EnableAccountRights( FALSE, 1, rights );
  829. //
  830. // Just for backward compatible, ignore error
  831. //
  832. rights[0] = SE_INTERACTIVE_LOGON_NAME;
  833. dwStatus = EnableAccountRights( FALSE, 1, rights );
  834. //
  835. // Just for backward compatible, ignore error
  836. //
  837. hRes = S_OK;
  838. }
  839. if( SUCCEEDED(hRes) )
  840. {
  841. //
  842. // TS setup always overwrite default security on upgrade.
  843. //
  844. //
  845. // Give user all rights except SeRemoteInterativeRights, Whilster does
  846. // not use WINSTATION_CONNECT any more.
  847. hRes = SetupHelpAccountTSRights(
  848. FALSE, // Not deleting, refer to ModifyUserAccess()
  849. TRUE, // enable TS rights
  850. TRUE, // delete existing entry if exist.
  851. WINSTATION_ALL_ACCESS // (WINSTATION_ALL_ACCESS) & ~(WINSTATION_CONNECT | WINSTATION_SET | WINSTATION_RESET)
  852. );
  853. }
  854. CLEANUPANDEXIT:
  855. return hRes;
  856. }
  857. HRESULT
  858. __HelpAssistantAccount::ConfigHelpAccountTSSettings(
  859. IN LPTSTR pszUserName,
  860. IN LPTSTR pszInitProgram
  861. )
  862. /*++
  863. Routine Description:
  864. This routine configurate TS specific settings
  865. for user account.
  866. Parameters:
  867. pszUserName : Name of user account to configurate.
  868. pszInitProgram : Full path to init. program when user
  869. login.
  870. Returns:
  871. ERROR_SUCCESS or error code
  872. --*/
  873. {
  874. BOOL bStatus;
  875. HRESULT hRes = S_OK;
  876. HMODULE hWtsapi32 = NULL;
  877. PWTSSetUserConfigW pConfig = NULL;
  878. BOOL bManualSetConsole = TRUE;
  879. BOOL bEnable;
  880. DWORD dwStatus;
  881. //DebugPrintf( _TEXT("SetupHelpAccountTSSettings...\n") );
  882. CCriticalSectionLocker l(gm_HelpAccountCS);
  883. dwStatus = IsLocalAccountEnabled(
  884. pszUserName,
  885. &bEnable
  886. );
  887. if( ERROR_SUCCESS != dwStatus )
  888. {
  889. //MYASSERT(FALSE);
  890. hRes = HRESULT_FROM_WIN32( dwStatus );
  891. return hRes;
  892. }
  893. hWtsapi32 = LoadLibrary( _TEXT("wtsapi32.dll") );
  894. if( NULL != hWtsapi32 )
  895. {
  896. pConfig = (PWTSSetUserConfigW)GetProcAddress(
  897. hWtsapi32,
  898. "WTSSetUserConfigW"
  899. );
  900. if( NULL != pConfig )
  901. {
  902. DWORD dwSettings;
  903. //
  904. // Set WTSUserConfigfAllowLogonTerminalServer
  905. //
  906. dwSettings = TRUE;
  907. bStatus = (pConfig)(
  908. NULL,
  909. pszUserName,
  910. WTSUserConfigfAllowLogonTerminalServer,
  911. (LPWSTR)&dwSettings,
  912. sizeof(dwSettings)
  913. );
  914. if( FALSE == bStatus )
  915. {
  916. bStatus = TRUE;
  917. }
  918. // MYASSERT( TRUE == bStatus );
  919. if( TRUE == bStatus )
  920. {
  921. //
  922. // Ignore all error and continue on setting values
  923. // catch error at the calling routine
  924. //
  925. dwSettings = TRUE;
  926. // Reset connection when connection broken
  927. bStatus = (pConfig)(
  928. NULL,
  929. pszUserName,
  930. WTSUserConfigBrokenTimeoutSettings,
  931. (LPWSTR)&dwSettings,
  932. sizeof(dwSettings)
  933. );
  934. dwSettings = FALSE;
  935. // initial program
  936. bStatus = (pConfig)(
  937. NULL,
  938. pszUserName,
  939. WTSUserConfigfInheritInitialProgram,
  940. (LPWSTR)&dwSettings,
  941. sizeof(dwSettings)
  942. );
  943. dwSettings = FALSE;
  944. // No re-connect.
  945. bStatus = (pConfig)(
  946. NULL,
  947. pszUserName,
  948. WTSUserConfigReconnectSettings,
  949. (LPWSTR)&dwSettings,
  950. sizeof(dwSettings)
  951. );
  952. dwSettings = FALSE;
  953. // No drive mapping
  954. bStatus = (pConfig)(
  955. NULL,
  956. pszUserName,
  957. WTSUserConfigfDeviceClientDrives,
  958. (LPWSTR)&dwSettings,
  959. sizeof(dwSettings)
  960. );
  961. dwSettings = FALSE;
  962. // No printer.
  963. bStatus = (pConfig)(
  964. NULL,
  965. pszUserName,
  966. WTSUserConfigfDeviceClientPrinters,
  967. (LPWSTR)&dwSettings,
  968. sizeof(dwSettings)
  969. );
  970. dwSettings = FALSE;
  971. // No defaultPrinter
  972. bStatus = (pConfig)(
  973. NULL,
  974. pszUserName,
  975. WTSUserConfigfDeviceClientDefaultPrinter,
  976. (LPWSTR)&dwSettings,
  977. sizeof(dwSettings)
  978. );
  979. bStatus = (pConfig)(
  980. NULL,
  981. pszUserName,
  982. WTSUserConfigInitialProgram,
  983. pszInitProgram,
  984. wcslen(pszInitProgram)
  985. );
  986. TCHAR path_buffer[MAX_PATH+1];
  987. TCHAR drive[_MAX_DRIVE + 1];
  988. TCHAR dir[_MAX_DIR + 1];
  989. memset( path_buffer, 0, sizeof(path_buffer) );
  990. _tsplitpath( pszInitProgram, drive, dir, NULL, NULL );
  991. wsprintf( path_buffer, L"%s%s", drive, dir );
  992. bStatus = (pConfig)(
  993. NULL,
  994. pszUserName,
  995. WTSUserConfigWorkingDirectory,
  996. path_buffer,
  997. wcslen(path_buffer)
  998. );
  999. }
  1000. if( FALSE == bStatus )
  1001. {
  1002. hRes = HRESULT_FROM_WIN32( GetLastError() );
  1003. }
  1004. } // end (pConfig != NULL)
  1005. }
  1006. if( NULL != hWtsapi32 )
  1007. {
  1008. FreeLibrary( hWtsapi32 );
  1009. }
  1010. //DebugPrintf( _TEXT("SetupHelpAccountTSSettings() ended...\n") );
  1011. return hRes;
  1012. }
  1013. HRESULT
  1014. __HelpAssistantAccount::SetupHelpAccountTSRights(
  1015. IN BOOL bDel,
  1016. IN BOOL bEnable,
  1017. IN BOOL bDeleteExisting,
  1018. IN DWORD dwPermissions
  1019. )
  1020. /*++
  1021. Routine Description:
  1022. This routine configurate TS specific settings
  1023. for user account.
  1024. Parameters:
  1025. pszUserName : Name of user account to configurate.
  1026. bDel : TRUE to delete account, FALSE otherwise.
  1027. bEnable : TRUE if enable, FALSE otherwise.
  1028. dwPermissions : Permission to be enable or disable
  1029. Returns:
  1030. ERROR_SUCCESS or error code
  1031. Note:
  1032. Refer to cfgbkend.idl for bDel and bEnable parameter.
  1033. --*/
  1034. {
  1035. BOOL bStatus;
  1036. HRESULT hRes = S_OK;
  1037. CComPtr<ICfgComp> tsccICfgComp;
  1038. IUserSecurity* tsccIUserSecurity = NULL;
  1039. DWORD dwNumWinStations = 0;
  1040. DWORD dwWinStationSize = 0;
  1041. PWS pWinStationList = NULL;
  1042. DWORD index;
  1043. DWORD dwCfgStatus = ERROR_SUCCESS;
  1044. BOOL bManualSetConsole = TRUE;
  1045. ULONG cbSecDescLen;
  1046. CCriticalSectionLocker l(gm_HelpAccountCS);
  1047. CoInitialize(NULL);
  1048. //hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  1049. hRes = tsccICfgComp.CoCreateInstance( CLSID_CfgComp );
  1050. if( FAILED(hRes) )
  1051. {
  1052. DebugPrintf( _TEXT("CoCreateInstance() failed with error code 0x%08x\n"), hRes );
  1053. //MYASSERT(FALSE);
  1054. goto CLEANUPANDEXIT;
  1055. }
  1056. hRes = tsccICfgComp->Initialize();
  1057. if( FAILED(hRes) )
  1058. {
  1059. DebugPrintf( _TEXT("tsccICfgComp->Initialize() failed with error code 0x%08x\n"), hRes );
  1060. // MYASSERT(FALSE);
  1061. goto CLEANUPANDEXIT;
  1062. }
  1063. hRes = tsccICfgComp->QueryInterface(
  1064. IID_IUserSecurity,
  1065. reinterpret_cast<void **>(&tsccIUserSecurity)
  1066. );
  1067. if( FAILED(hRes) || NULL == tsccIUserSecurity)
  1068. {
  1069. DebugPrintf( _TEXT("QueryInterface() failed with error code 0x%08x\n"), hRes );
  1070. // MYASSERT(FALSE);
  1071. goto CLEANUPANDEXIT;
  1072. }
  1073. //
  1074. // Setting Default security shadow permission
  1075. //
  1076. hRes = tsccIUserSecurity->ModifyDefaultSecurity(
  1077. L"",
  1078. gm_bstrHelpAccountName,
  1079. dwPermissions,
  1080. bDel,
  1081. bEnable,
  1082. FALSE,
  1083. &dwCfgStatus
  1084. );
  1085. if( FAILED(hRes) || ERROR_SUCCESS != dwCfgStatus )
  1086. {
  1087. DebugPrintf(
  1088. _TEXT("ModifyDefaultSecurity on default security return 0x%08x, dwCfgStatus = %d\n"),
  1089. hRes,
  1090. dwCfgStatus
  1091. );
  1092. // MYASSERT(FALSE);
  1093. //
  1094. // Continue on to setting wtsapi32, we still can
  1095. // RDS on non-console winstation
  1096. //
  1097. hRes = S_OK;
  1098. dwCfgStatus = ERROR_SUCCESS;
  1099. }
  1100. // retrieve a list of winstation name
  1101. hRes = tsccICfgComp->GetWinstationList(
  1102. &dwNumWinStations,
  1103. &dwWinStationSize,
  1104. &pWinStationList
  1105. );
  1106. if( FAILED(hRes) )
  1107. {
  1108. DebugPrintf( _TEXT("QueryInterface() failed with error code 0x%08x\n"), hRes );
  1109. goto CLEANUPANDEXIT;
  1110. }
  1111. //
  1112. // Set TS Logon permission on all winstation
  1113. //
  1114. for( index = 0; index < dwNumWinStations && ERROR_SUCCESS == dwCfgStatus && SUCCEEDED(hRes); index ++ )
  1115. {
  1116. if( 0 == _tcsicmp( pWinStationList[index].Name, L"Console" ) )
  1117. {
  1118. bManualSetConsole = FALSE;
  1119. }
  1120. dwCfgStatus = 0;
  1121. //DebugPrintf( _TEXT("Name of Winstation : %s\n"), pWinStationList[index].Name );
  1122. // check if custom security exist for this winstation
  1123. dwCfgStatus = RegWinStationQuerySecurity(
  1124. SERVERNAME_CURRENT,
  1125. pWinStationList[index].Name,
  1126. NULL,
  1127. 0,
  1128. &cbSecDescLen
  1129. );
  1130. if( ERROR_INSUFFICIENT_BUFFER == dwCfgStatus )
  1131. {
  1132. DebugPrintf( _TEXT("Winstation : %s has custom security\n"), pWinStationList[index].Name );
  1133. // From TS Setup, Insufficient buffer means the winstation has custom security
  1134. hRes = tsccIUserSecurity->ModifyUserAccess(
  1135. pWinStationList[index].Name,
  1136. gm_bstrHelpAccountName,
  1137. dwPermissions,
  1138. bDel,
  1139. bEnable,
  1140. bDeleteExisting,
  1141. FALSE,
  1142. &dwCfgStatus
  1143. );
  1144. if( FAILED(hRes) || ERROR_SUCCESS != dwCfgStatus )
  1145. {
  1146. DebugPrintf(
  1147. _TEXT("ModifyUserAccess return 0x%08x, dwCfgStatus = %d\n"),
  1148. hRes,
  1149. dwCfgStatus
  1150. );
  1151. // MYASSERT(FALSE);
  1152. continue;
  1153. }
  1154. }
  1155. else if( ERROR_FILE_NOT_FOUND == dwCfgStatus )
  1156. {
  1157. // no custom security for this winstation
  1158. dwCfgStatus = ERROR_SUCCESS;
  1159. }
  1160. else
  1161. {
  1162. DebugPrintf(
  1163. _TEXT("RegWinStationQuerySecurity returns %d\n"),
  1164. dwCfgStatus
  1165. );
  1166. // MYASSERT(FALSE);
  1167. }
  1168. }
  1169. if( ERROR_SUCCESS != dwCfgStatus || FAILED(hRes) )
  1170. {
  1171. DebugPrintf(
  1172. _TEXT("ModifyUserAccess() Loop failed - 0x%08x, %d...\n"),
  1173. hRes, dwCfgStatus
  1174. );
  1175. goto CLEANUPANDEXIT;
  1176. }
  1177. if( TRUE == bManualSetConsole )
  1178. {
  1179. //
  1180. // Setting Console shadow permission, we don't know when GetWinstationList()
  1181. // will return us Console so...
  1182. //
  1183. hRes = tsccIUserSecurity->ModifyUserAccess(
  1184. L"Console",
  1185. gm_bstrHelpAccountName,
  1186. dwPermissions,
  1187. bDel,
  1188. bEnable,
  1189. bDeleteExisting,
  1190. FALSE,
  1191. &dwCfgStatus
  1192. );
  1193. if( FAILED(hRes) || ERROR_SUCCESS != dwCfgStatus )
  1194. {
  1195. DebugPrintf(
  1196. _TEXT("ModifyUserAccess on console return 0x%08x, dwCfgStatus = %d\n"),
  1197. hRes,
  1198. dwCfgStatus
  1199. );
  1200. // MYASSERT(FALSE);
  1201. //
  1202. // Continue on to setting wtsapi32, we still can
  1203. // RDS on non-console winstation
  1204. //
  1205. hRes = S_OK;
  1206. dwCfgStatus = ERROR_SUCCESS;
  1207. // goto CLEANUPANDEXIT;
  1208. }
  1209. }
  1210. if( SUCCEEDED(hRes) )
  1211. {
  1212. tsccICfgComp->ForceUpdate();
  1213. }
  1214. CLEANUPANDEXIT:
  1215. if( NULL != pWinStationList )
  1216. {
  1217. CoTaskMemFree( pWinStationList );
  1218. }
  1219. if( NULL != tsccIUserSecurity )
  1220. {
  1221. tsccIUserSecurity->Release();
  1222. }
  1223. if( tsccICfgComp )
  1224. {
  1225. tsccICfgComp.Release();
  1226. }
  1227. //DebugPrintf( _TEXT("SetupHelpAssistantTermSrvPermissions() ended...\n") );
  1228. CoUninitialize();
  1229. return hRes;
  1230. }
  1231. HRESULT
  1232. __HelpAssistantAccount::ResetHelpAccountPassword(
  1233. IN LPCTSTR pszPassword
  1234. )
  1235. /*++
  1236. Routine Description:
  1237. This routine change help assistant account password and
  1238. store corresponding password to LSA.
  1239. Parameters:
  1240. None.
  1241. Returns:
  1242. ERROR_SUCCESS or error code.
  1243. Note:
  1244. If help account is disable or not present on local machine,
  1245. we assume no help can be done on local machine.
  1246. --*/
  1247. {
  1248. DWORD dwStatus;
  1249. BOOL bEnabled;
  1250. TCHAR szNewPassword[MAX_HELPACCOUNT_PASSWORD+1];
  1251. CCriticalSectionLocker l(gm_HelpAccountCS);
  1252. memset(
  1253. szNewPassword,
  1254. 0,
  1255. sizeof(szNewPassword)
  1256. );
  1257. //
  1258. // Check if help assistant account is enabled.
  1259. //
  1260. dwStatus = IsLocalAccountEnabled(
  1261. gm_bstrHelpAccountName,
  1262. &bEnabled
  1263. );
  1264. if( ERROR_SUCCESS != dwStatus )
  1265. {
  1266. dwStatus = SESSMGR_E_HELPACCOUNT;
  1267. goto CLEANUPANDEXIT;
  1268. }
  1269. //
  1270. // Account is disable, don't reset password
  1271. //
  1272. if( FALSE == bEnabled )
  1273. {
  1274. // help account is disabled, no help is available from this box
  1275. DebugPrintf(
  1276. _TEXT("Account is disabled...\n")
  1277. );
  1278. dwStatus = SESSMGR_E_HELPACCOUNT;
  1279. goto CLEANUPANDEXIT;
  1280. }
  1281. //
  1282. // if account is enabled, re-set password
  1283. //
  1284. if( NULL == pszPassword || 0 == lstrlen(pszPassword) )
  1285. {
  1286. // we are asked to generate a random password,
  1287. // bail out if can't create random password
  1288. dwStatus = CreatePassword( szNewPassword );
  1289. if( ERROR_SUCCESS != dwStatus )
  1290. {
  1291. MYASSERT( FALSE );
  1292. goto CLEANUPANDEXIT;
  1293. }
  1294. }
  1295. else
  1296. {
  1297. memset(
  1298. szNewPassword,
  1299. 0,
  1300. sizeof(szNewPassword)
  1301. );
  1302. _tcsncpy(
  1303. szNewPassword,
  1304. pszPassword,
  1305. min(lstrlen(pszPassword), MAX_HELPACCOUNT_PASSWORD)
  1306. );
  1307. }
  1308. //
  1309. // Change the password and cache with LSA, if caching failed
  1310. // reset password back to what we have before.
  1311. //
  1312. dwStatus = ChangeLocalAccountPassword(
  1313. gm_bstrHelpAccountName,
  1314. gm_bstrHelpAccountPwd,
  1315. szNewPassword
  1316. );
  1317. if( ERROR_SUCCESS == dwStatus )
  1318. {
  1319. //
  1320. // save the password with LSA
  1321. //
  1322. dwStatus = StoreKeyWithLSA(
  1323. HELPASSISTANTACCOUNT_PASSWORDKEY,
  1324. (PBYTE) szNewPassword,
  1325. (lstrlen(szNewPassword)+1) * sizeof(TCHAR)
  1326. );
  1327. if( ERROR_SUCCESS != dwStatus )
  1328. {
  1329. DWORD dwStatus1;
  1330. //
  1331. // something wrong with storing password, reset password
  1332. // back so we can recover next time.
  1333. //
  1334. dwStatus1 = ChangeLocalAccountPassword(
  1335. gm_bstrHelpAccountName,
  1336. szNewPassword,
  1337. gm_bstrHelpAccountPwd
  1338. );
  1339. if( ERROR_SUCCESS != dwStatus1 )
  1340. {
  1341. //
  1342. // we have a big problem here, should we delete the account
  1343. // and recreate one again?
  1344. //
  1345. }
  1346. }
  1347. else
  1348. {
  1349. //
  1350. // make a copy of new password.
  1351. //
  1352. gm_bstrHelpAccountPwd = szNewPassword;
  1353. }
  1354. }
  1355. CLEANUPANDEXIT:
  1356. return HRESULT_FROM_WIN32(dwStatus);
  1357. }
  1358. DWORD
  1359. __HelpAssistantAccount::EnableAccountRights(
  1360. BOOL bEnable,
  1361. DWORD dwNumRights,
  1362. LPTSTR* rights
  1363. )
  1364. /*++
  1365. --*/
  1366. {
  1367. DWORD dwStatus;
  1368. LSA_UNICODE_STRING UserRightString[1];
  1369. LSA_HANDLE PolicyHandle = NULL;
  1370. //
  1371. // create an lsa policy for it
  1372. dwStatus = OpenPolicy(
  1373. NULL,
  1374. POLICY_ALL_ACCESS,
  1375. &PolicyHandle
  1376. );
  1377. if( ERROR_SUCCESS == dwStatus )
  1378. {
  1379. for( DWORD i=0; i < dwNumRights && ERROR_SUCCESS == dwStatus ; i++ )
  1380. {
  1381. DebugPrintf(
  1382. _TEXT("%s Help Assistant rights %s\n"),
  1383. (bEnable) ? _TEXT("Enable") : _TEXT("Disable"),
  1384. rights[i]
  1385. );
  1386. // Remote interactive right
  1387. InitLsaString(
  1388. UserRightString,
  1389. rights[i]
  1390. );
  1391. if( bEnable )
  1392. {
  1393. dwStatus = LsaAddAccountRights(
  1394. PolicyHandle,
  1395. gm_pbHelpAccountSid,
  1396. UserRightString,
  1397. 1
  1398. );
  1399. }
  1400. else
  1401. {
  1402. dwStatus = LsaRemoveAccountRights(
  1403. PolicyHandle,
  1404. gm_pbHelpAccountSid,
  1405. FALSE,
  1406. UserRightString,
  1407. 1
  1408. );
  1409. }
  1410. DebugPrintf(
  1411. _TEXT("\tEnable/disable account rights %s returns 0x%08x\n"),
  1412. rights[i],
  1413. dwStatus
  1414. );
  1415. if( dwStatus == STATUS_NO_SUCH_PRIVILEGE )
  1416. {
  1417. dwStatus = ERROR_SUCCESS;
  1418. }
  1419. }
  1420. LsaClose(PolicyHandle);
  1421. }
  1422. return dwStatus;
  1423. }
  1424. HRESULT
  1425. __HelpAssistantAccount::EnableRemoteInteractiveRight(
  1426. IN BOOL bEnable
  1427. )
  1428. /*++
  1429. Routine Description:
  1430. Routine to enable/disable Help Assistant account remote interactive
  1431. logon rights.
  1432. Parameters:
  1433. bEnable : TRUE to enable, FALSE to disable.
  1434. Returns:
  1435. S_OK or error code.
  1436. --*/
  1437. {
  1438. LPTSTR rights[1];
  1439. DWORD dwStatus;
  1440. rights[0] = SE_REMOTE_INTERACTIVE_LOGON_NAME;
  1441. dwStatus = EnableAccountRights( bEnable, 1, rights );
  1442. return HRESULT_FROM_WIN32(dwStatus);
  1443. }
  1444. BOOL
  1445. __HelpAssistantAccount::IsAccountHelpAccount(
  1446. IN PBYTE pbSid,
  1447. IN DWORD cbSid
  1448. )
  1449. /*++
  1450. Routine Description:
  1451. Check if a user is Help Assistant.
  1452. Parameters:
  1453. pbSid : Pointer to user SID to checked.
  1454. cbSid : Size of user SID.
  1455. Returns:
  1456. TRUE/FALSE
  1457. --*/
  1458. {
  1459. BOOL bSuccess = FALSE;
  1460. if( NULL != pbSid )
  1461. {
  1462. // make sure it is a valid sid.
  1463. bSuccess = IsValidSid( (PSID)pbSid );
  1464. if( FALSE == bSuccess )
  1465. {
  1466. SetLastError( ERROR_INVALID_SID );
  1467. }
  1468. else
  1469. {
  1470. bSuccess = EqualSid( gm_pbHelpAccountSid, pbSid );
  1471. if( FALSE == bSuccess )
  1472. {
  1473. SetLastError( ERROR_INVALID_DATA );
  1474. }
  1475. }
  1476. }
  1477. return bSuccess;
  1478. }
  1479. HRESULT
  1480. __HelpAssistantAccount::EnableHelpAssistantAccount(
  1481. BOOL bEnable
  1482. )
  1483. /*++
  1484. --*/
  1485. {
  1486. DWORD dwStatus;
  1487. dwStatus = EnableLocalAccount( gm_bstrHelpAccountName, bEnable );
  1488. DebugPrintf(
  1489. _TEXT("%s %s returns %d\n"),
  1490. gm_bstrHelpAccountName,
  1491. (bEnable) ? _TEXT("Enable") : _TEXT("Disable"),
  1492. dwStatus
  1493. );
  1494. return HRESULT_FROM_WIN32( dwStatus );
  1495. }