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.

1128 lines
27 KiB

  1. /************************************************************************
  2. Copyright (c) 2000 - 2000 Microsoft Corporation
  3. Module Name :
  4. logontable.cpp
  5. Abstract :
  6. Source file for the logon table.
  7. Author :
  8. Revision History :
  9. ***********************************************************************/
  10. #include "stdafx.h"
  11. #include <winsta.h>
  12. #include <wtsapi32.h>
  13. #include <userenv.h>
  14. #include "logontable.tmh"
  15. HRESULT DetectTerminalServer( bool * pfTS );
  16. HRESULT
  17. GetUserToken(
  18. ULONG LogonId,
  19. PHANDLE pUserToken
  20. );
  21. HRESULT
  22. WaitForUserToken(
  23. DWORD session,
  24. HANDLE * pToken
  25. )
  26. {
  27. const MaxWait = 30 * 1000;
  28. const WaitInterval = 500;
  29. long StartTime = GetTickCount();
  30. HRESULT Hr = E_FAIL;
  31. do
  32. {
  33. Hr = GetUserToken( session, pToken );
  34. if ( SUCCEEDED( Hr ) )
  35. return Hr;
  36. LogError("logon : unable to get token : %!winerr!", Hr );
  37. Sleep( WaitInterval );
  38. }
  39. while ( GetTickCount() - StartTime < MaxWait );
  40. return Hr;
  41. }
  42. CLoggedOnUsers::CLoggedOnUsers(
  43. TaskScheduler & sched
  44. ) : m_TaskScheduler( sched ),
  45. m_SensNotifier( NULL )
  46. {
  47. FILETIME time;
  48. GetSystemTimeAsFileTime( &time );
  49. m_CurrentCookie = time.dwLowDateTime;
  50. if ( WINDOWS2000_PLATFORM == g_PlatformVersion )
  51. {
  52. try
  53. {
  54. bool fTS;
  55. THROW_HRESULT( DetectTerminalServer( &fTS ));
  56. if (fTS)
  57. {
  58. m_SensNotifier = new CTerminalServerLogonNotification;
  59. LogInfo( "TS-enabled SENS notification activated" );
  60. }
  61. else
  62. {
  63. m_SensNotifier = new CLogonNotification;
  64. LogInfo( "regular SENS notification activated" );
  65. }
  66. }
  67. catch( ComError Error )
  68. {
  69. if ( Error.Error() == TYPE_E_CANTLOADLIBRARY ||
  70. Error.Error() == TYPE_E_LIBNOTREGISTERED )
  71. {
  72. LogInfo( "SENS doesn't exist on this platform, skipping" );
  73. return;
  74. }
  75. else
  76. {
  77. LogInfo("SENS object failed with %x", Error.Error() );
  78. throw;
  79. }
  80. }
  81. }
  82. }
  83. CLoggedOnUsers::~CLoggedOnUsers()
  84. {
  85. if (m_SensNotifier)
  86. {
  87. m_SensNotifier->DeRegisterNotification();
  88. m_SensNotifier->Release();
  89. }
  90. }
  91. HRESULT
  92. CLoggedOnUsers::LogonSession(
  93. DWORD session
  94. )
  95. {
  96. CUser * user = NULL;
  97. try
  98. {
  99. HANDLE Token = NULL;
  100. auto_HANDLE<NULL> AutoToken;
  101. //
  102. // Get the user's token and SID, then create a user object.
  103. //
  104. THROW_HRESULT( WaitForUserToken( session, &Token ));
  105. ASSERT( Token ); // Token can't be NULL
  106. AutoToken = Token;
  107. user = new CUser( Token );
  108. //
  109. // Add the user to our by-session and by-SID indexes.
  110. //
  111. HoldWriterLock lock ( m_TaskScheduler );
  112. try
  113. {
  114. // Just in case...delete any previously recorded user.
  115. //
  116. LogoffSession( session );
  117. //
  118. // Subtlety: if the node for m_ActiveSessions[ session ] doesn't exist,
  119. // then the first reference to it will cause a node to be allocated. This may
  120. // throw E_OUTOFMEMORY.
  121. //
  122. m_ActiveSessions[ session ] = user;
  123. m_ActiveUsers.insert( make_pair( user->QuerySid(), user ) );
  124. }
  125. catch( ComError Error )
  126. {
  127. m_ActiveSessions.erase( session );
  128. throw;
  129. }
  130. Dump();
  131. g_Manager->UserLoggedOn( user->QuerySid() );
  132. return S_OK;
  133. }
  134. catch( ComError err )
  135. {
  136. delete user;
  137. LogError("logon : returning error 0x%x", err.Error() );
  138. Dump();
  139. return err.Error();
  140. }
  141. }
  142. HRESULT
  143. CLoggedOnUsers::LogoffSession(
  144. DWORD session
  145. )
  146. {
  147. try
  148. {
  149. HoldWriterLock lock ( m_TaskScheduler );
  150. CUser * user = m_ActiveSessions[ session ];
  151. if (!user)
  152. return S_OK;
  153. bool b = m_ActiveUsers.RemovePair( user->QuerySid(), user );
  154. ASSERT( b );
  155. m_ActiveSessions.erase( session );
  156. Dump();
  157. if (false == g_Manager->IsUserLoggedOn( user->QuerySid() ))
  158. {
  159. g_Manager->UserLoggedOff( user->QuerySid() );
  160. }
  161. user->DecrementRefCount();
  162. return S_OK;
  163. }
  164. catch( ComError err )
  165. {
  166. LogWarning("logoff : exception 0x%x thrown", err.Error());
  167. Dump();
  168. return err.Error();
  169. }
  170. }
  171. CUser *
  172. CLoggedOnUsers::CUserList::FindSid(
  173. SidHandle sid
  174. )
  175. {
  176. iterator iter = find( sid );
  177. if (iter == end())
  178. {
  179. return NULL;
  180. }
  181. return iter->second;
  182. }
  183. bool
  184. CLoggedOnUsers::CUserList::RemovePair(
  185. SidHandle sid,
  186. CUser * user
  187. )
  188. {
  189. //
  190. // Find the user in the user list and delete it.
  191. //
  192. pair<iterator, iterator> b = equal_range( sid );
  193. for (iterator i = b.first; i != b.second; ++i)
  194. {
  195. if (i->second == user)
  196. {
  197. erase( i );
  198. return true;
  199. }
  200. }
  201. return false;
  202. }
  203. CUser *
  204. CLoggedOnUsers::CUserList::RemoveByCookie(
  205. SidHandle sid,
  206. DWORD cookie
  207. )
  208. {
  209. //
  210. // Find the user in the user list and delete it.
  211. //
  212. pair<iterator, iterator> b = equal_range( sid );
  213. for (iterator i = b.first; i != b.second; ++i)
  214. {
  215. CUser * user = i->second;
  216. if (user->GetCookie() == cookie)
  217. {
  218. erase( i );
  219. return user;
  220. }
  221. }
  222. return NULL;
  223. }
  224. HRESULT
  225. CLoggedOnUsers::LogonService(
  226. HANDLE Token,
  227. DWORD * pCookie
  228. )
  229. {
  230. CUser * user = NULL;
  231. try
  232. {
  233. user = new CUser( Token );
  234. *pCookie = InterlockedIncrement( &m_CurrentCookie );
  235. user->SetCookie( *pCookie );
  236. HoldWriterLock lock ( m_TaskScheduler );
  237. m_ActiveServiceAccounts.insert( make_pair( user->QuerySid(), user ));
  238. return S_OK;
  239. }
  240. catch( ComError err )
  241. {
  242. delete user;
  243. LogError("logon service : returning error 0x%x", err.Error() );
  244. return err.Error();
  245. }
  246. }
  247. HRESULT
  248. CLoggedOnUsers::LogoffService(
  249. SidHandle Sid,
  250. DWORD Cookie
  251. )
  252. {
  253. try
  254. {
  255. HoldWriterLock lock ( m_TaskScheduler );
  256. CUser * user = m_ActiveServiceAccounts.RemoveByCookie( Sid, Cookie );
  257. if (!user)
  258. {
  259. LogWarning("logoff : invalid cookie %d", Cookie);
  260. return E_INVALIDARG;
  261. }
  262. user->DecrementRefCount();
  263. return S_OK;
  264. }
  265. catch( ComError err)
  266. {
  267. LogWarning("logoff : exception 0x%x thrown", err.Error());
  268. return err.Error();
  269. }
  270. }
  271. HRESULT
  272. CLoggedOnUsers::AddServiceAccounts()
  273. {
  274. HRESULT hr = S_OK;
  275. DWORD ignore;
  276. HoldWriterLock lock ( m_TaskScheduler );
  277. //
  278. // Add the LOCAL_SYSTEM account.
  279. //
  280. HANDLE Token;
  281. if (OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY | TOKEN_DUPLICATE, &Token ))
  282. {
  283. hr = LogonService( Token, &ignore );
  284. CloseHandle( Token );
  285. }
  286. else
  287. {
  288. hr = HRESULT_FROM_WIN32( GetLastError() );
  289. }
  290. if (FAILED(hr))
  291. {
  292. LogWarning( "failed to register LocalSystem : %!winerr!", hr );
  293. return hr;
  294. }
  295. if (g_PlatformVersion >= WINDOWSXP_PLATFORM)
  296. {
  297. //
  298. // Add the LocalService account.
  299. //
  300. if (LogonUser( L"LocalService",
  301. L"NT AUTHORITY",
  302. L"",
  303. LOGON32_LOGON_SERVICE,
  304. LOGON32_PROVIDER_DEFAULT,
  305. &Token))
  306. {
  307. hr = LogonService( Token, &ignore );
  308. CloseHandle( Token );
  309. }
  310. else
  311. {
  312. hr = HRESULT_FROM_WIN32( GetLastError() );
  313. }
  314. if (FAILED(hr))
  315. {
  316. LogWarning( "failed to register LocalService : %!winerr!", hr );
  317. if ( HRESULT_FROM_WIN32( ERROR_LOGON_FAILURE ) == hr )
  318. LogWarning( "LocalService doesn't exist, skip it.\n");
  319. else
  320. return hr;
  321. }
  322. //
  323. // Add the NetworkService account.
  324. //
  325. if (LogonUser( L"NetworkService",
  326. L"NT AUTHORITY",
  327. L"",
  328. LOGON32_LOGON_SERVICE,
  329. LOGON32_PROVIDER_DEFAULT,
  330. &Token))
  331. {
  332. hr = LogonService( Token, &ignore );
  333. CloseHandle( Token );
  334. }
  335. else
  336. {
  337. hr = HRESULT_FROM_WIN32( GetLastError() );
  338. }
  339. if (FAILED(hr))
  340. {
  341. LogWarning( "failed to register NetworkService : %!winerr!", hr );
  342. if ( HRESULT_FROM_WIN32( ERROR_LOGON_FAILURE ) == hr )
  343. LogWarning( "NetworkService doesn't exist, skip it.\n");
  344. else
  345. return hr;
  346. }
  347. }
  348. //
  349. // done
  350. //
  351. return S_OK;
  352. }
  353. HRESULT
  354. CLoggedOnUsers::AddActiveUsers()
  355. {
  356. HRESULT hr = S_OK;
  357. WTS_SESSION_INFO * SessionInfo = 0;
  358. HANDLE Token;
  359. HoldWriterLock lock ( m_TaskScheduler );
  360. //
  361. // Get the console token, if any, without using Terminal Services.
  362. //
  363. if ( SUCCEEDED( GetUserToken( 0, &Token) ) )
  364. {
  365. CloseHandle( Token );
  366. hr = LogonSession( 0 );
  367. if (FAILED(hr))
  368. {
  369. // ignore it and try to carry on...
  370. LogWarning( "service : unable to logon session zero : %!winerr!", hr );
  371. }
  372. }
  373. //
  374. // The call may return FALSE, because Terminal Services is not always loaded.
  375. //
  376. DWORD SessionCount = 0;
  377. BOOL b = WTSEnumerateSessions( WTS_CURRENT_SERVER_HANDLE,
  378. 0, // reserved
  379. 1, // version 1 is the only supported v.
  380. &SessionInfo,
  381. &SessionCount
  382. );
  383. if (b)
  384. {
  385. int i;
  386. for (i=0; i < SessionCount; ++i)
  387. {
  388. if (SessionInfo[i].SessionId == 0)
  389. {
  390. // console was handled by GetCurrentUserToken.
  391. continue;
  392. }
  393. if (SessionInfo[i].State == WTSActive ||
  394. SessionInfo[i].State == WTSDisconnected)
  395. {
  396. LogInfo("service : logon session %d, state %d",
  397. SessionInfo[i].SessionId,
  398. SessionInfo[i].State );
  399. hr = LogonSession( SessionInfo[i].SessionId );
  400. if (FAILED(hr))
  401. {
  402. // ignore it and try to carry on...
  403. LogWarning( "service : unable to logon session %d : %!winerr!",
  404. SessionInfo[i].SessionId,
  405. hr );
  406. }
  407. }
  408. }
  409. }
  410. if (SessionInfo)
  411. {
  412. WTSFreeMemory( SessionInfo );
  413. }
  414. //
  415. // Now that the current population is recorded, keep abreast of changes.
  416. //
  417. if (m_SensNotifier)
  418. {
  419. m_SensNotifier->SetEnableState( true );
  420. }
  421. return S_OK;
  422. }
  423. CUser *
  424. CLoggedOnUsers::FindUser(
  425. SidHandle sid,
  426. DWORD session
  427. )
  428. {
  429. HoldReaderLock lock ( m_TaskScheduler );
  430. CUser * user = 0;
  431. //
  432. // Look for a session with the right user.
  433. //
  434. if (session == ANY_SESSION)
  435. {
  436. user = m_ActiveUsers.FindSid( sid );
  437. }
  438. else
  439. {
  440. try
  441. {
  442. user = m_ActiveSessions[ session ];
  443. if (user && user->QuerySid() != sid)
  444. {
  445. user = 0;
  446. }
  447. }
  448. catch( ComError Error )
  449. {
  450. user = 0;
  451. }
  452. }
  453. //
  454. // Look in the service account list, if the session is compatible.
  455. //
  456. if (!user && (session == 0 || session == ANY_SESSION))
  457. {
  458. user = m_ActiveServiceAccounts.FindSid( sid );
  459. }
  460. if (user)
  461. {
  462. user->IncrementRefCount();
  463. }
  464. return user;
  465. }
  466. void CLoggedOnUsers::Dump()
  467. {
  468. HoldReaderLock lock ( m_TaskScheduler );
  469. LogInfo("sessions:");
  470. m_ActiveSessions.Dump();
  471. LogInfo("users:");
  472. m_ActiveUsers.Dump();
  473. LogInfo("service accounts:");
  474. m_ActiveServiceAccounts.Dump();
  475. }
  476. void CLoggedOnUsers::CSessionList::Dump()
  477. {
  478. for (iterator iter = begin(); iter != end(); ++iter)
  479. {
  480. LogInfo(" session %d user %p", iter->first, iter->second);
  481. }
  482. }
  483. void CLoggedOnUsers::CUserList::Dump()
  484. {
  485. for (iterator iter = begin(); iter != end(); ++iter)
  486. {
  487. if (iter->second)
  488. {
  489. (iter->second)->Dump();
  490. }
  491. }
  492. }
  493. CLoggedOnUsers::CUserList::~CUserList()
  494. {
  495. iterator iter;
  496. while ((iter=begin()) != end())
  497. {
  498. delete iter->second;
  499. erase( iter );
  500. }
  501. }
  502. void CUser::Dump()
  503. {
  504. LogInfo( " user at %p:", this);
  505. LogInfo( " %d refs, sid %!sid!", _ReferenceCount, _Sid.get());
  506. }
  507. long CUser::IncrementRefCount()
  508. {
  509. long count = InterlockedIncrement( & _ReferenceCount );
  510. LogRef("refs %d", count);
  511. return count;
  512. }
  513. long CUser::DecrementRefCount()
  514. {
  515. long count = InterlockedDecrement( & _ReferenceCount );
  516. LogRef("refs %d", count);
  517. if (0 == count)
  518. {
  519. delete this;
  520. }
  521. return count;
  522. }
  523. CUser::CUser(
  524. HANDLE Token
  525. )
  526. /*++
  527. Routine Description:
  528. Initializes a new CUser.
  529. At entry:
  530. <Sid> points to the user's SID.
  531. <Token> points to the user's token. It can be an impersonation or primary token.
  532. <phr> points to an error-return variable.
  533. At exit:
  534. The CUser is set up. The caller can delete <Sid> and <Token> if it wants to.
  535. if an error occurs, it is mapped to an HRESULT and written to <phr>.
  536. otherwise <*phr> is untouched and the CUser is ready for use.
  537. --*/
  538. {
  539. _ReferenceCount = 1;
  540. _Sid = CopyTokenSid( Token );
  541. //
  542. // Copy the token. Whether the source is primary or impersonation,
  543. // the result will be a primary token.
  544. //
  545. if (!DuplicateHandle(
  546. GetCurrentProcess(),
  547. Token,
  548. GetCurrentProcess(),
  549. &_Token,
  550. TOKEN_ALL_ACCESS,
  551. FALSE, // not inheritable
  552. 0 // no funny options
  553. ))
  554. {
  555. HRESULT HrError = HRESULT_FROM_WIN32( GetLastError() );
  556. LogError( "CUser: can't duplicate token %!winerr!", HrError );
  557. throw ComError( HrError );
  558. }
  559. }
  560. CUser::~CUser()
  561. {
  562. CloseHandle( _Token );
  563. }
  564. HRESULT
  565. CUser::LaunchProcess(
  566. StringHandle Program,
  567. StringHandle Parameters
  568. )
  569. {
  570. DWORD s;
  571. PVOID EnvironmentBlock = 0;
  572. PROCESS_INFORMATION ProcessInformation;
  573. memset( &ProcessInformation, 0, sizeof( PROCESS_INFORMATION ));
  574. try
  575. {
  576. STARTUPINFO si;
  577. memset( &si, 0, sizeof( STARTUPINFO ));
  578. si.cb = sizeof(STARTUPINFO);
  579. //
  580. // Parameters must be a writable string for some reason.
  581. //
  582. CAutoString WritableParms( CopyString( LPCWSTR(Parameters) ));
  583. LogInfo( "creating process: cmd line: '%S' '%S'", Program, WritableParms.get() );
  584. if (!CreateEnvironmentBlock( &EnvironmentBlock,
  585. _Token,
  586. FALSE
  587. ))
  588. {
  589. ThrowLastError();
  590. }
  591. //
  592. // Need to impersonate the token so that the program file is accessed as the user.
  593. // Otherwise launching a UNC path would fail, and the job would also be able to
  594. // launch local programs otherwise inaccessible to the job owner.
  595. //
  596. CNestedImpersonation imp( _Token );
  597. if (!CreateProcessAsUser( _Token,
  598. Program,
  599. WritableParms.get(),
  600. 0, // no special security attributes
  601. 0, // no special thread attributes
  602. false, // don't inherit my handles
  603. NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT,
  604. EnvironmentBlock,
  605. NULL, // default current directory
  606. &si,
  607. &ProcessInformation
  608. ))
  609. {
  610. ThrowLastError();
  611. }
  612. DestroyEnvironmentBlock( EnvironmentBlock );
  613. EnvironmentBlock = 0;
  614. CloseHandle( ProcessInformation.hThread );
  615. ProcessInformation.hThread = 0;
  616. CloseHandle( ProcessInformation.hProcess );
  617. ProcessInformation.hProcess = 0;
  618. LogInfo("success, pid is 0x%x", ProcessInformation.dwProcessId);
  619. //
  620. // We succeeded.
  621. //
  622. return S_OK;
  623. }
  624. catch ( ComError err )
  625. {
  626. LogError("unable to create process, %x", err.Error() );
  627. if (EnvironmentBlock)
  628. {
  629. DestroyEnvironmentBlock( EnvironmentBlock );
  630. }
  631. return err.Error();
  632. }
  633. }
  634. #if ENABLE_STL_LOCK_OVERRIDE
  635. /*
  636. This file implements the STL lockit class to avoid linking to msvcprt.dll.
  637. */
  638. CCritSec CrtLock;
  639. #pragma warning(push)
  640. #pragma warning(disable:4273) // __declspec(dllimport) attribute overridden
  641. std::_Lockit::_Lockit()
  642. {
  643. CrtLock.WriteLock();
  644. }
  645. std::_Lockit::~_Lockit()
  646. {
  647. CrtLock.WriteUnlock();
  648. }
  649. #pragma warning(pop)
  650. #endif
  651. extern "C"
  652. {
  653. HANDLE
  654. GetCurrentUserTokenW(
  655. WCHAR Winsta[],
  656. DWORD DesiredAccess
  657. );
  658. void * __RPC_USER MIDL_user_allocate(size_t size)
  659. {
  660. try
  661. {
  662. return new char[size];
  663. }
  664. catch( ComError Error )
  665. {
  666. return NULL;
  667. }
  668. }
  669. void __RPC_USER MIDL_user_free( void * block)
  670. {
  671. delete block;
  672. }
  673. }
  674. HRESULT
  675. GetUserToken(
  676. ULONG LogonId,
  677. PHANDLE pUserToken
  678. )
  679. {
  680. //
  681. // Win2000 compatibility is important only for x86 builds.
  682. //
  683. #if defined(_X86_) && defined(MULTIPLATFORM_SUPPORT)
  684. if (g_PlatformVersion == WINDOWS2000_PLATFORM)
  685. {
  686. //
  687. // This gets the token of the user logged onto the WinStation
  688. // if we are an admin caller.
  689. //
  690. if (LogonId == 0)
  691. {
  692. // don't need the TS API.
  693. *pUserToken = GetCurrentUserTokenW( L"WinSta0", TOKEN_ALL_ACCESS );
  694. if (*pUserToken != NULL)
  695. {
  696. return S_OK;
  697. }
  698. // if not, try the TS API.
  699. }
  700. //
  701. // Use Terminal Services for non-console Logon IDs.
  702. //
  703. BOOL Result;
  704. ULONG ReturnLength;
  705. NTSTATUS Status;
  706. OBJECT_ATTRIBUTES ObjA;
  707. HANDLE ImpersonationToken;
  708. WINSTATIONUSERTOKEN Info;
  709. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  710. static PWINSTATIONQUERYINFORMATIONW pWinstationQueryInformation = 0;
  711. //
  712. // See if the entry point is loaded yet.
  713. //
  714. if (!pWinstationQueryInformation)
  715. {
  716. HMODULE module = LoadLibrary(_T("winsta.dll"));
  717. if (module == NULL)
  718. {
  719. HRESULT HrError = HRESULT_FROM_WIN32( GetLastError() );
  720. ASSERT( S_OK != HrError );
  721. LogInfo( "Load library of winsta failed, error %!winerr!", HrError );
  722. return HrError;
  723. }
  724. pWinstationQueryInformation = (PWINSTATIONQUERYINFORMATIONW) GetProcAddress( module, "WinStationQueryInformationW" );
  725. if (!pWinstationQueryInformation)
  726. {
  727. HRESULT HrError = HRESULT_FROM_WIN32( GetLastError() );
  728. ASSERT( S_OK != HrError );
  729. LogInfo( "GetProcAddress of WinStationQueryInformationW, error %!winerr!", HrError );
  730. FreeLibrary(module);
  731. return HrError;
  732. }
  733. }
  734. //
  735. // Ask for the token.
  736. //
  737. Info.ProcessId = UlongToHandle(GetCurrentProcessId());
  738. Info.ThreadId = UlongToHandle(GetCurrentThreadId());
  739. Result = (*pWinstationQueryInformation)(
  740. SERVERNAME_CURRENT,
  741. LogonId,
  742. WinStationUserToken,
  743. &Info,
  744. sizeof(Info),
  745. &ReturnLength
  746. );
  747. if( !Result )
  748. {
  749. HRESULT HrError = HRESULT_FROM_WIN32( GetLastError() );
  750. ASSERT( S_OK != HrError );
  751. LogError("token : WinstationQueryInfo failed with %!winerr!%", HrError );
  752. return HrError;
  753. }
  754. //
  755. // The token returned is a duplicate of a primary token.
  756. //
  757. *pUserToken = Info.UserToken;
  758. return S_OK;
  759. }
  760. else
  761. #endif // _X86_ and MULTIPLATFORM_SUPPORT
  762. {
  763. typedef BOOL (WINAPI * PWTSQUERYUSERTOKEN)( ULONG SessionId, PHANDLE phToken );
  764. static PWTSQUERYUSERTOKEN pWtsQueryUserToken = 0;
  765. //
  766. // See if the entry point is loaded yet.
  767. //
  768. if (!pWtsQueryUserToken)
  769. {
  770. HMODULE module = LoadLibrary(_T("wtsapi32.dll"));
  771. if (module == NULL)
  772. {
  773. DWORD s = GetLastError();
  774. ASSERT( s != 0 );
  775. LogInfo( "Load library of winsta failed, error %!winerr!", s );
  776. return HRESULT_FROM_WIN32( s );
  777. }
  778. pWtsQueryUserToken = (PWTSQUERYUSERTOKEN) GetProcAddress( module, "WTSQueryUserToken" );
  779. if (!pWtsQueryUserToken)
  780. {
  781. DWORD s = GetLastError();
  782. ASSERT( s != 0 );
  783. LogInfo( "GetProcAddress of WTSQueryUserToken, error %!winerr!", s );
  784. FreeLibrary(module);
  785. return HRESULT_FROM_WIN32( s );
  786. }
  787. }
  788. //
  789. // Ask for the token.
  790. //
  791. if (!(*pWtsQueryUserToken)( LogonId, pUserToken ))
  792. {
  793. return HRESULT_FROM_WIN32( GetLastError() );
  794. }
  795. return S_OK;
  796. }
  797. }
  798. BOOL
  799. SidToString(
  800. PSID sid,
  801. wchar_t buffer[],
  802. USHORT bytes
  803. )
  804. {
  805. UNICODE_STRING UnicodeString;
  806. UnicodeString.Buffer = buffer;
  807. UnicodeString.Length = 0;
  808. UnicodeString.MaximumLength = bytes;
  809. NTSTATUS NtStatus;
  810. NtStatus = RtlConvertSidToUnicodeString( &UnicodeString,
  811. sid,
  812. FALSE
  813. );
  814. if (!NT_SUCCESS(NtStatus))
  815. {
  816. LogWarning( "RtlConvertSid failed %x", NtStatus);
  817. StringCbCopy( buffer, bytes, L"(conversion failed)" );
  818. return FALSE;
  819. }
  820. buffer[ UnicodeString.Length ] = 0;
  821. return TRUE;
  822. }
  823. HRESULT
  824. SetStaticCloaking(
  825. IUnknown *pUnk
  826. )
  827. {
  828. // Sets static cloaking on the current object so that we
  829. // should always impersonate the current context.
  830. // Also sets the impersonation level to identify.
  831. HRESULT Hr = S_OK;
  832. IClientSecurity *pSecurity = NULL;
  833. OLECHAR *ServerPrincName = NULL;
  834. try
  835. {
  836. Hr = pUnk->QueryInterface( __uuidof( IClientSecurity ),
  837. (void**)&pSecurity );
  838. if (Hr == E_NOINTERFACE)
  839. {
  840. //
  841. // This is not a proxy; the client is in the same apartment as we are.
  842. // Identity issn't an issue, because the client already has access to system
  843. // credentials.
  844. //
  845. return S_OK;
  846. }
  847. DWORD AuthnSvc, AuthzSvc;
  848. DWORD AuthnLevel, ImpLevel, Capabilites;
  849. THROW_HRESULT(
  850. pSecurity->QueryBlanket(
  851. pUnk,
  852. &AuthnSvc,
  853. &AuthzSvc,
  854. &ServerPrincName,
  855. &AuthnLevel,
  856. NULL, // Don't need impersonation handle since were setting that
  857. NULL, // don't need indenty handle since were setting that
  858. &Capabilites ) );
  859. THROW_HRESULT(
  860. pSecurity->SetBlanket(
  861. pUnk,
  862. AuthnSvc,
  863. AuthzSvc,
  864. ServerPrincName,
  865. AuthnLevel,
  866. RPC_C_IMP_LEVEL_IDENTIFY,
  867. NULL, // COM use indentity from token
  868. EOAC_STATIC_CLOAKING // The point of the exercise
  869. ) );
  870. }
  871. catch( ComError Error )
  872. {
  873. Hr = Error.Error();
  874. }
  875. CoTaskMemFree( ServerPrincName );
  876. SafeRelease( pSecurity );
  877. return Hr;
  878. }
  879. HRESULT DetectTerminalServer( bool * pfTS )
  880. /*
  881. This function checks whether Terminal Services is installed. This is the "official" way to check
  882. for machines running Win2000 and above.
  883. */
  884. {
  885. OSVERSIONINFOEX osVersionInfo;
  886. DWORDLONG dwlConditionMask = 0;
  887. ZeroMemory(&osVersionInfo, sizeof(OSVERSIONINFOEX));
  888. osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  889. osVersionInfo.wSuiteMask = VER_SUITE_TERMINAL;
  890. VER_SET_CONDITION( dwlConditionMask, VER_SUITENAME, VER_AND );
  891. if (0 != VerifyVersionInfo(
  892. &osVersionInfo,
  893. VER_SUITENAME,
  894. dwlConditionMask
  895. ))
  896. {
  897. LogInfo("TS test: TS is installed");
  898. *pfTS = true;
  899. return S_OK;
  900. }
  901. DWORD s = GetLastError();
  902. if (s == ERROR_OLD_WIN_VERSION)
  903. {
  904. LogInfo("TS test: no TS");
  905. *pfTS = false;
  906. return S_OK;
  907. }
  908. LogError("TS test returned %d", s);
  909. return HRESULT_FROM_WIN32( s );
  910. }