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.

1494 lines
39 KiB

  1. //=============================================================================
  2. // session.cpp -- implementation of session collection class.
  3. //
  4. // Copyright (c) 1998-2002 Microsoft Corporation, All Rights Reserved
  5. //=============================================================================
  6. #include <nt.h>
  7. #include <ntrtl.h>
  8. #include <nturtl.h>
  9. #include <ntobapi.h>
  10. #define _WINNT_ // have what is needed from above
  11. #pragma warning (disable: 4786)
  12. #include "precomp.h"
  13. #include <map>
  14. #include <vector>
  15. #include <comdef.h>
  16. #include "chstring.h"
  17. #include "session.h"
  18. #include <ProvExce.h>
  19. #include <AssertBreak.h>
  20. #include <wbemcli.h>
  21. #include <ntsecapi.h>
  22. #ifdef _WIN32_WINNT
  23. #define SECURITY_WIN32
  24. #else
  25. #define SECURITY_WIN16
  26. #endif
  27. #include <sspi.h>
  28. #include "ctoken.h"
  29. #include <autoptr.h>
  30. #include <ScopeGuard.h>
  31. typedef SECURITY_STATUS (SEC_ENTRY *PFN_LSA_ENUMERATE_LOGON_SESSIONS)
  32. (
  33. OUT PULONG LogonSessionCount,
  34. OUT PLUID* LogonSessionList
  35. );
  36. typedef SECURITY_STATUS (SEC_ENTRY *PFN_LSA_GET_LOGON_SESSION_DATA)
  37. (
  38. IN PLUID LogonId,
  39. OUT PSECURITY_LOGON_SESSION_DATA* ppLogonSessionData
  40. );
  41. typedef NTSTATUS (*PFN_LSA_FREE_RETURN_BUFFER)
  42. (
  43. IN PVOID Buffer
  44. );
  45. //*****************************************************************************
  46. // CUserSessionCollection functions
  47. //*****************************************************************************
  48. CUserSessionCollection::CUserSessionCollection()
  49. {
  50. Refresh();
  51. }
  52. CUserSessionCollection::CUserSessionCollection(
  53. const CUserSessionCollection& sescol)
  54. {
  55. m_usr2ses.clear();
  56. USER_SESSION_ITERATOR sourceIter;
  57. for(sourceIter = sescol.m_usr2ses.begin();
  58. sourceIter != sescol.m_usr2ses.end();
  59. sourceIter++)
  60. {
  61. m_usr2ses.insert(
  62. USER_SESSION_MAP::value_type(
  63. sourceIter->first,
  64. sourceIter->second));
  65. }
  66. }
  67. DWORD CUserSessionCollection::Refresh()
  68. {
  69. DWORD dwRet = ERROR_SUCCESS;
  70. // Empty out previous contents...
  71. m_usr2ses.clear();
  72. dwRet = CollectSessions();
  73. return dwRet;
  74. }
  75. DWORD CUserSessionCollection::CollectSessions()
  76. {
  77. DWORD dwRet = ERROR_SUCCESS;
  78. std::vector<CProcess> vecProcesses;
  79. SmartCloseHandle hProcess;
  80. SmartCloseHandle hToken;
  81. TOKEN_STATISTICS tokstats;
  82. PTOKEN_USER ptokusr = NULL;
  83. DWORD dwRetSize = 0L;
  84. PSID psidUsr = NULL;
  85. CHString chstrUsr;
  86. LUID luidSes;
  87. // Enable the debug privilege...
  88. EnablePrivilegeOnCurrentThread(SE_DEBUG_NAME);
  89. // Get a list of all running processes...
  90. dwRet = GetProcessList(vecProcesses);
  91. if(dwRet == ERROR_SUCCESS)
  92. {
  93. // For each member of the process list...
  94. for(long m = 0L;
  95. m < vecProcesses.size();
  96. m++)
  97. {
  98. // open the process...
  99. ::SetLastError(ERROR_SUCCESS);
  100. dwRet = ERROR_SUCCESS;
  101. hProcess = ::OpenProcess(
  102. PROCESS_QUERY_INFORMATION,
  103. FALSE,
  104. vecProcesses[m].GetPID());
  105. if(hProcess == NULL)
  106. {
  107. dwRet = ::GetLastError();
  108. }
  109. // get the process token...
  110. if(hProcess != NULL &&
  111. dwRet == ERROR_SUCCESS)
  112. {
  113. ::SetLastError(ERROR_SUCCESS);
  114. dwRet = ERROR_SUCCESS;
  115. if(!::OpenProcessToken(
  116. hProcess,
  117. TOKEN_QUERY,
  118. &hToken))
  119. {
  120. dwRet = ::GetLastError();
  121. }
  122. }
  123. // get the token statistics...
  124. if(hToken != NULL &&
  125. dwRet == ERROR_SUCCESS)
  126. {
  127. ::SetLastError(ERROR_SUCCESS);
  128. dwRet = ERROR_SUCCESS;
  129. if(!::GetTokenInformation(
  130. hToken,
  131. TokenStatistics,
  132. &tokstats,
  133. sizeof(TOKEN_STATISTICS),
  134. &dwRetSize))
  135. {
  136. dwRet = ::GetLastError();
  137. }
  138. }
  139. //
  140. // smart token user
  141. //
  142. wmilib::auto_buffer < BYTE > smartptokusr;
  143. // get the token user sid...
  144. if(dwRet == ERROR_SUCCESS)
  145. {
  146. // the token user struct varries
  147. // in size depending on the size
  148. // of the sid in the SID_AND_ATTRIBUTES
  149. // structure, so need to allocate
  150. // it dynamically.
  151. if(!::GetTokenInformation(
  152. hToken,
  153. TokenUser,
  154. NULL,
  155. 0L,
  156. &dwRetSize))
  157. {
  158. dwRet = ::GetLastError();
  159. }
  160. if(dwRet == ERROR_INSUFFICIENT_BUFFER)
  161. {
  162. smartptokusr.reset ( new BYTE [ dwRetSize ] ) ;
  163. ptokusr = (PTOKEN_USER) smartptokusr.get () ;
  164. DWORD dwTmp = dwRetSize;
  165. if(!::GetTokenInformation(
  166. hToken,
  167. TokenUser,
  168. ptokusr,
  169. dwTmp,
  170. &dwRetSize))
  171. {
  172. dwRet = ::GetLastError();
  173. }
  174. else
  175. {
  176. dwRet = ERROR_SUCCESS ;
  177. }
  178. }
  179. }
  180. if(ptokusr != NULL)
  181. {
  182. if(dwRet == ERROR_SUCCESS)
  183. {
  184. psidUsr = (ptokusr->User).Sid;
  185. // from the token statistics, get
  186. // the TokenID LUID of the session...
  187. luidSes.LowPart = tokstats.AuthenticationId.LowPart;
  188. luidSes.HighPart = tokstats.AuthenticationId.HighPart;
  189. // try to find the session of the
  190. // process in the multimap...
  191. USER_SESSION_ITERATOR usiter;
  192. if(FindSessionInternal(
  193. luidSes,
  194. usiter))
  195. {
  196. // try to find the process id in the
  197. // session's process vector...
  198. CSession sesTmp(usiter->second);
  199. CProcess* procTmp = NULL;
  200. bool fFoundIt = false;
  201. for(long z = 0L;
  202. z < sesTmp.m_vecProcesses.size() && !fFoundIt;
  203. z++)
  204. {
  205. if((DWORD)(sesTmp.m_vecProcesses[z].GetPID()) ==
  206. vecProcesses[m].GetPID())
  207. {
  208. fFoundIt = true;
  209. }
  210. }
  211. // If we didn't find the process in the
  212. // session's list of processes, add it in...
  213. if(!fFoundIt)
  214. {
  215. (usiter->second).m_vecProcesses.push_back(
  216. CProcess(vecProcesses[m]));
  217. }
  218. }
  219. else // no such session in the map, so add an entry
  220. {
  221. // Create new CSession(tokenid LUID), and
  222. // add process to the session's process vector...
  223. CSession sesNew(luidSes);
  224. sesNew.m_vecProcesses.push_back(
  225. vecProcesses[m]);
  226. // add CUser(user sid) to map.first and the
  227. // CSession just created to map.second...
  228. CUser cuTmp(psidUsr);
  229. if(cuTmp.IsValid())
  230. {
  231. m_usr2ses.insert(
  232. USER_SESSION_MAP::value_type(
  233. cuTmp,
  234. sesNew));
  235. }
  236. else
  237. {
  238. LogErrorMessage2(
  239. L"Token of process %d contains an invalid sid",
  240. vecProcesses[m].GetPID());
  241. }
  242. }
  243. }
  244. }
  245. } // next process
  246. }
  247. // There may have been sessions not associated
  248. // with any processes. To get these, we will
  249. // use LSA.
  250. CollectNoProcessesSessions();
  251. return dwRet;
  252. }
  253. void CUserSessionCollection::Copy(
  254. CUserSessionCollection& out) const
  255. {
  256. out.m_usr2ses.clear();
  257. USER_SESSION_ITERATOR meIter;
  258. for(meIter = m_usr2ses.begin();
  259. meIter != m_usr2ses.end();
  260. meIter++)
  261. {
  262. out.m_usr2ses.insert(
  263. USER_SESSION_MAP::value_type(
  264. meIter->first,
  265. meIter->second));
  266. }
  267. }
  268. // Support enumeration of users. Returns
  269. // a newly allocated copy of what was in
  270. // the map (caller must free).
  271. CUser* CUserSessionCollection::GetFirstUser(
  272. USER_SESSION_ITERATOR& pos)
  273. {
  274. CUser* cusrRet = NULL;
  275. if(!m_usr2ses.empty())
  276. {
  277. pos = m_usr2ses.begin();
  278. cusrRet = new CUser(pos->first);
  279. }
  280. return cusrRet;
  281. }
  282. // Returns a newly allocated CUser*, which
  283. // the caller must free.
  284. CUser* CUserSessionCollection::GetNextUser(
  285. USER_SESSION_ITERATOR& pos)
  286. {
  287. // Users are the non-unique part of
  288. // the map, so we need to go through
  289. // the map until the next user entry
  290. // comes up.
  291. CUser* usrRet = NULL;
  292. while(pos != m_usr2ses.end())
  293. {
  294. CHString chstrSidCur;
  295. pos->first.GetSidString(chstrSidCur);
  296. pos++;
  297. if(pos != m_usr2ses.end())
  298. {
  299. CHString chstrSidNext;
  300. pos->first.GetSidString(chstrSidNext);
  301. // Return the first instance where
  302. // the next user is different from
  303. // the current one.
  304. if(chstrSidNext.CompareNoCase(chstrSidCur) != 0)
  305. {
  306. usrRet = new CUser(pos->first);
  307. break;
  308. }
  309. }
  310. }
  311. return usrRet;
  312. }
  313. // Support enumeration of sessions
  314. // belonging to a particular user.
  315. CSession* CUserSessionCollection::GetFirstSessionOfUser(
  316. CUser& usr,
  317. USER_SESSION_ITERATOR& pos)
  318. {
  319. CSession* csesRet = NULL;
  320. if(!m_usr2ses.empty())
  321. {
  322. pos = m_usr2ses.find(usr);
  323. if(pos != m_usr2ses.end())
  324. {
  325. csesRet = new CSession(pos->second);
  326. }
  327. }
  328. return csesRet;
  329. }
  330. CSession* CUserSessionCollection::GetNextSessionOfUser(
  331. USER_SESSION_ITERATOR& pos)
  332. {
  333. // Sessions are the unique part of
  334. // the map, so we just need to get
  335. // the next one as long as pos.first
  336. // matches usr...
  337. CSession* sesRet = NULL;
  338. if(pos != m_usr2ses.end())
  339. {
  340. CHString chstrUsr1;
  341. CHString chstrUsr2;
  342. (pos->first).GetSidString(chstrUsr1);
  343. pos++;
  344. if(pos != m_usr2ses.end())
  345. {
  346. (pos->first).GetSidString(chstrUsr2);
  347. if(chstrUsr1.CompareNoCase(chstrUsr2) == 0)
  348. {
  349. sesRet = new CSession(pos->second);
  350. }
  351. }
  352. }
  353. return sesRet;
  354. }
  355. // Support enumeration of all sessions. Returns a
  356. // newly allocated CSession*, which the caller
  357. // must free.
  358. CSession* CUserSessionCollection::GetFirstSession(
  359. USER_SESSION_ITERATOR& pos)
  360. {
  361. CSession* csesRet = NULL;
  362. if(!m_usr2ses.empty())
  363. {
  364. pos = m_usr2ses.begin();
  365. csesRet = new CSession(pos->second);
  366. }
  367. return csesRet;
  368. }
  369. // Returns a newly allocated CSession* that the
  370. // caller must free.
  371. CSession* CUserSessionCollection::GetNextSession(
  372. USER_SESSION_ITERATOR& pos)
  373. {
  374. // Sessions are the unique part of
  375. // the map, so we just need to get
  376. // the next one...
  377. CSession* sesRet = NULL;
  378. if(pos != m_usr2ses.end())
  379. {
  380. pos++;
  381. if(pos != m_usr2ses.end())
  382. {
  383. sesRet = new CSession(pos->second);
  384. }
  385. }
  386. return sesRet;
  387. }
  388. // Support finding a particular session.
  389. // This internal version hands back an iterator
  390. // on our member map that points to the found
  391. // instance if found (when the function returns
  392. // true. If the function returns
  393. // false, the iterator points to the end of our
  394. // map.
  395. bool CUserSessionCollection::FindSessionInternal(
  396. LUID& luidSes,
  397. USER_SESSION_ITERATOR& usiOut)
  398. {
  399. bool fFoundIt = false;
  400. for(usiOut = m_usr2ses.begin();
  401. usiOut != m_usr2ses.end();
  402. usiOut++)
  403. {
  404. LUID luidTmp = (usiOut->second).GetLUID();
  405. if(luidTmp.HighPart == luidSes.HighPart &&
  406. luidTmp.LowPart == luidSes.LowPart)
  407. {
  408. fFoundIt = true;
  409. break;
  410. }
  411. }
  412. return fFoundIt;
  413. }
  414. // Support finding a particular session - external
  415. // callers can call this one, and are given a new
  416. // CSession* they can play with.
  417. CSession* CUserSessionCollection::FindSession(
  418. LUID& luidSes)
  419. {
  420. CSession* psesRet = NULL;
  421. USER_SESSION_ITERATOR pos;
  422. if(FindSessionInternal(
  423. luidSes,
  424. pos))
  425. {
  426. psesRet = new CSession(pos->second);
  427. }
  428. return psesRet;
  429. }
  430. CSession* CUserSessionCollection::FindSession(
  431. __int64 i64luidSes)
  432. {
  433. LUID luidSes = *((LUID*)(&i64luidSes));
  434. return FindSession(luidSes);
  435. }
  436. // Support enumeration of processes
  437. // belonging to a particular user. Returns
  438. // newly allocated CProcess* which the caller
  439. // must free.
  440. CProcess* CUserSessionCollection::GetFirstProcessOfUser(
  441. CUser& usr,
  442. USER_SESSION_PROCESS_ITERATOR& pos)
  443. {
  444. CProcess* cprocRet = NULL;
  445. CHString chstrUsrSidStr;
  446. CHString chstrTmp;
  447. if(!m_usr2ses.empty())
  448. {
  449. usr.GetSidString(chstrUsrSidStr);
  450. pos.usIter = m_usr2ses.find(usr);
  451. while(pos.usIter != m_usr2ses.end())
  452. {
  453. // Get the sid string of the user we
  454. // are at and see whether the strings
  455. // are the same (e.g., whether this is a
  456. // session associated with the specified
  457. // user)...
  458. (pos.usIter)->first.GetSidString(chstrTmp);
  459. if(chstrUsrSidStr.CompareNoCase(chstrTmp) == 0)
  460. {
  461. // Now check that the session of the user
  462. // we are on has processes...
  463. if(!(((pos.usIter)->second).m_vecProcesses.empty()))
  464. {
  465. pos.procIter =
  466. ((pos.usIter)->second).m_vecProcesses.begin();
  467. cprocRet = new CProcess(*(pos.procIter));
  468. }
  469. else
  470. {
  471. // the session for this user has
  472. // no processes, so go to the next
  473. // session...
  474. (pos.usIter)++;
  475. }
  476. }
  477. }
  478. }
  479. return cprocRet;
  480. }
  481. // Returns a newly allocated CProcess* that the
  482. // caller must free.
  483. CProcess* CUserSessionCollection::GetNextProcessOfUser(
  484. USER_SESSION_PROCESS_ITERATOR& pos)
  485. {
  486. CProcess* cprocRet = NULL;
  487. CHString chstrCurUsr;
  488. CHString chstrNxtSesUsr;
  489. if(pos.usIter != m_usr2ses.end())
  490. {
  491. (pos.usIter)->first.GetSidString(chstrCurUsr);
  492. while(pos.usIter != m_usr2ses.end())
  493. {
  494. // First try to get the next process
  495. // within the current session. If we
  496. // were at the end of the list of processes
  497. // for the current session, go to the
  498. // next session...
  499. (pos.procIter)++;
  500. // Of course, if we have moved on
  501. // to a different user, then stop.
  502. (pos.usIter)->first.GetSidString(chstrNxtSesUsr);
  503. if(chstrCurUsr.CompareNoCase(chstrNxtSesUsr) == 0)
  504. {
  505. if(pos.procIter ==
  506. ((pos.usIter)->second).m_vecProcesses.end())
  507. {
  508. (pos.usIter)++;
  509. }
  510. else
  511. {
  512. cprocRet = new CProcess(*(pos.procIter));
  513. }
  514. }
  515. }
  516. }
  517. return cprocRet;
  518. }
  519. // Support enumeration of all processes. Returns
  520. // newly allocated CProcess* which the caller
  521. // must free.
  522. CProcess* CUserSessionCollection::GetFirstProcess(
  523. USER_SESSION_PROCESS_ITERATOR& pos)
  524. {
  525. CProcess* cprocRet = NULL;
  526. if(!m_usr2ses.empty())
  527. {
  528. pos.usIter = m_usr2ses.begin();
  529. while(pos.usIter != m_usr2ses.end())
  530. {
  531. if(!(((pos.usIter)->second).m_vecProcesses.empty()))
  532. {
  533. pos.procIter =
  534. ((pos.usIter)->second).m_vecProcesses.begin();
  535. cprocRet = new CProcess(*(pos.procIter));
  536. }
  537. else
  538. {
  539. (pos.usIter)++;
  540. }
  541. }
  542. }
  543. return cprocRet;
  544. }
  545. // Returns a newly allocated CProcess* that the
  546. // caller must free.
  547. CProcess* CUserSessionCollection::GetNextProcess(
  548. USER_SESSION_PROCESS_ITERATOR& pos)
  549. {
  550. CProcess* cprocRet = NULL;
  551. while(pos.usIter != m_usr2ses.end())
  552. {
  553. // First try to get the next process
  554. // within the current session. If we
  555. // were at the end of the list of processes
  556. // for the current session, go to the
  557. // next session...
  558. (pos.procIter)++;
  559. if(pos.procIter ==
  560. ((pos.usIter)->second).m_vecProcesses.end())
  561. {
  562. (pos.usIter)++;
  563. }
  564. else
  565. {
  566. cprocRet = new CProcess(*(pos.procIter));
  567. }
  568. }
  569. return cprocRet;
  570. }
  571. // This helper enumerates the current set of processes
  572. // and ads each process id as a DWORD in the vector.
  573. DWORD CUserSessionCollection::GetProcessList( std::vector<CProcess>& vecProcesses ) const
  574. {
  575. DWORD dwRet = ERROR_SUCCESS;
  576. // First, load up ntdll...
  577. HMODULE hLib = NULL;
  578. PFN_NT_QUERY_SYSTEM_INFORMATION pfnNtQuerySystemInformation = NULL;
  579. hLib = LoadLibraryW(L"NTDLL.DLL");
  580. if(hLib != NULL)
  581. {
  582. //
  583. // auto FreeLibrary
  584. //
  585. ON_BLOCK_EXIT ( FreeLibrary, hLib ) ;
  586. // Get proc address of NtQuerySystemInformation...
  587. pfnNtQuerySystemInformation = (PFN_NT_QUERY_SYSTEM_INFORMATION)
  588. GetProcAddress(
  589. hLib,
  590. "NtQuerySystemInformation");
  591. if(pfnNtQuerySystemInformation != NULL)
  592. {
  593. // Ready to rock. Enable debug priv...
  594. EnablePrivilegeOnCurrentThread(SE_DEBUG_NAME);
  595. DWORD dwProcessInformationSize = 0;
  596. SYSTEM_PROCESS_INFORMATION* ProcessInformation = NULL;
  597. //
  598. // smart ProcessInformation
  599. //
  600. wmilib::auto_buffer < BYTE > SmartProcessInformation;
  601. // Get the process information...
  602. BOOL fRetry = TRUE;
  603. while(fRetry)
  604. {
  605. dwRet = pfnNtQuerySystemInformation(
  606. SystemProcessInformation,
  607. ProcessInformation,
  608. dwProcessInformationSize,
  609. NULL);
  610. if(dwRet == STATUS_INFO_LENGTH_MISMATCH)
  611. {
  612. dwProcessInformationSize += 32768;
  613. SmartProcessInformation.reset ( new BYTE [ dwProcessInformationSize ] );
  614. ProcessInformation = (SYSTEM_PROCESS_INFORMATION*)SmartProcessInformation.get () ;
  615. }
  616. else
  617. {
  618. fRetry = FALSE;
  619. }
  620. }
  621. // If we got the process information, process it...
  622. if(ProcessInformation != NULL &&
  623. dwRet == ERROR_SUCCESS)
  624. {
  625. SYSTEM_PROCESS_INFORMATION* CurrentInformation = NULL;
  626. DWORD dwNextOffset;
  627. CurrentInformation = ProcessInformation;
  628. bool fContinue = true;
  629. while(CurrentInformation != NULL &&
  630. fContinue)
  631. {
  632. {
  633. CProcess cptmp(
  634. HandleToUlong(CurrentInformation->UniqueProcessId),
  635. (CurrentInformation->ImageName).Buffer);
  636. vecProcesses.push_back(cptmp);
  637. }
  638. dwNextOffset = CurrentInformation->NextEntryOffset;
  639. if(dwNextOffset)
  640. {
  641. CurrentInformation = (SYSTEM_PROCESS_INFORMATION*)
  642. (((BYTE*) CurrentInformation) + dwNextOffset);
  643. }
  644. else
  645. {
  646. fContinue = false;
  647. }
  648. }
  649. }
  650. }
  651. }
  652. else
  653. {
  654. LogErrorMessage(L"Failed to load library ntdll.dll");
  655. }
  656. return dwRet;
  657. }
  658. // Implementation lifted from dllutils.cpp.
  659. DWORD CUserSessionCollection::EnablePrivilegeOnCurrentThread(
  660. LPCTSTR szPriv) const
  661. {
  662. SmartCloseHandle hToken = NULL;
  663. TOKEN_PRIVILEGES tkp;
  664. BOOL bLookup = FALSE;
  665. DWORD dwLastError = ERROR_SUCCESS;
  666. // Try to open the thread token.
  667. if (::OpenThreadToken(
  668. GetCurrentThread(),
  669. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  670. FALSE,
  671. &hToken))
  672. {
  673. {
  674. bLookup = ::LookupPrivilegeValue(
  675. NULL,
  676. szPriv,
  677. &tkp.Privileges[0].Luid);
  678. }
  679. if (bLookup)
  680. {
  681. tkp.PrivilegeCount = 1;
  682. tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  683. // Clear the last error.
  684. SetLastError(0);
  685. // Turn it on
  686. ::AdjustTokenPrivileges(
  687. hToken,
  688. FALSE,
  689. &tkp,
  690. 0,
  691. (PTOKEN_PRIVILEGES) NULL,
  692. 0);
  693. dwLastError = GetLastError();
  694. }
  695. }
  696. else
  697. {
  698. dwLastError = ::GetLastError();
  699. }
  700. // We have to check GetLastError() because
  701. // AdjustTokenPrivileges lies about
  702. // its success but GetLastError() doesn't.
  703. return dwLastError;
  704. }
  705. bool CUserSessionCollection::IsSessionMapped(
  706. LUID& luidSes)
  707. {
  708. bool fRet = false;
  709. USER_SESSION_ITERATOR usiter;
  710. usiter = m_usr2ses.begin();
  711. for(usiter = m_usr2ses.begin();
  712. usiter != m_usr2ses.end() && !fRet;
  713. usiter++)
  714. {
  715. LUID luidTmp = (usiter->second).GetLUID();
  716. if(luidTmp.HighPart == luidSes.HighPart &&
  717. luidTmp.LowPart == luidSes.LowPart)
  718. {
  719. fRet = true;
  720. }
  721. }
  722. return fRet;
  723. }
  724. bool CUserSessionCollection::IsSessionMapped(
  725. __int64 i64luidSes)
  726. {
  727. LUID luidSes = *((LUID*)(&i64luidSes));
  728. return IsSessionMapped(luidSes);
  729. }
  730. // Collects sessions that have no associated
  731. // process. Uses LSA to enumerate sessions,
  732. // then checks to see if we have each session
  733. // already. If we don't, adds it to our map.
  734. DWORD CUserSessionCollection::CollectNoProcessesSessions()
  735. {
  736. DWORD dwRet = ERROR_SUCCESS;
  737. ULONG ulLogonSessionCount = 0L;
  738. PLUID pluidLogonSessions = NULL;
  739. HMODULE hLib = NULL;
  740. PFN_LSA_ENUMERATE_LOGON_SESSIONS pfnEnumLogonSessions = NULL;
  741. PFN_LSA_GET_LOGON_SESSION_DATA pfnGetLogonSessionData = NULL;
  742. PFN_LSA_FREE_RETURN_BUFFER pfnLsaFreeReturnBuffer = NULL;
  743. // Doing a load library here rather than using the
  744. // resource manager, as SECURITYAPI.CPP defines us
  745. // to point to SECURITY.DLL, not SECUR32.DLL for the
  746. // W2K case.
  747. hLib = ::LoadLibraryW(L"SECUR32.DLL");
  748. if(hLib)
  749. {
  750. //
  751. // auto FreeLibrary
  752. //
  753. ON_BLOCK_EXIT ( FreeLibrary, hLib ) ;
  754. pfnEnumLogonSessions =
  755. (PFN_LSA_ENUMERATE_LOGON_SESSIONS) ::GetProcAddress(
  756. hLib,
  757. "LsaEnumerateLogonSessions");
  758. pfnGetLogonSessionData =
  759. (PFN_LSA_GET_LOGON_SESSION_DATA) ::GetProcAddress(
  760. hLib,
  761. "LsaGetLogonSessionData");
  762. pfnLsaFreeReturnBuffer =
  763. (PFN_LSA_FREE_RETURN_BUFFER) ::GetProcAddress(
  764. hLib,
  765. "LsaFreeReturnBuffer");
  766. if(pfnEnumLogonSessions &&
  767. pfnGetLogonSessionData &&
  768. pfnLsaFreeReturnBuffer)
  769. {
  770. dwRet = pfnEnumLogonSessions(
  771. &ulLogonSessionCount,
  772. &pluidLogonSessions);
  773. if(dwRet == ERROR_SUCCESS &&
  774. pluidLogonSessions)
  775. {
  776. //
  777. // auto destructor for logon session
  778. //
  779. ON_BLOCK_EXIT ( pfnLsaFreeReturnBuffer, pluidLogonSessions ) ;
  780. for(ULONG u = 0L;
  781. u < ulLogonSessionCount && dwRet == ERROR_SUCCESS;
  782. u++)
  783. {
  784. PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
  785. dwRet = pfnGetLogonSessionData(
  786. &pluidLogonSessions[u],
  787. &pSessionData);
  788. if(dwRet == ERROR_SUCCESS &&
  789. pSessionData)
  790. {
  791. //
  792. // smart session data
  793. //
  794. ON_BLOCK_EXIT ( pfnLsaFreeReturnBuffer, pSessionData ) ;
  795. // See if we have the session already...
  796. if(!IsSessionMapped(pSessionData->LogonId))
  797. {
  798. // and if not, add it to the map.
  799. CSession sesNew(pSessionData->LogonId);
  800. CUser cuTmp(pSessionData->Sid);
  801. CHString chstrTmp;
  802. if(cuTmp.IsValid())
  803. {
  804. cuTmp.GetSidString(chstrTmp);
  805. m_usr2ses.insert(
  806. USER_SESSION_MAP::value_type(
  807. cuTmp,
  808. sesNew));
  809. }
  810. else
  811. {
  812. LUID luidTmp = sesNew.GetLUID();
  813. LogMessage3(
  814. L"GetLogonSessionData returned logon data for session "
  815. L"luid %d (highpart) %u (lowpart) containing an invalid SID",
  816. luidTmp.HighPart,
  817. luidTmp.LowPart);
  818. }
  819. }
  820. // While we are here, add in various
  821. // session properties lsa has been kind
  822. // enough to provide for us.
  823. USER_SESSION_ITERATOR usiter;
  824. usiter = m_usr2ses.begin();
  825. bool fFound = false;
  826. while(usiter != m_usr2ses.end() &&
  827. !fFound)
  828. {
  829. LUID luidTmp = pSessionData->LogonId;
  830. __int64 i64Tmp = *((__int64*)(&luidTmp));
  831. if((usiter->second).GetLUIDint64() ==
  832. i64Tmp)
  833. {
  834. fFound = true;
  835. }
  836. else
  837. {
  838. usiter++;
  839. }
  840. }
  841. if(fFound)
  842. {
  843. WCHAR wstrTmp[_MAX_PATH] = { '\0' };
  844. if((pSessionData->AuthenticationPackage).Length < (_MAX_PATH - 1))
  845. {
  846. wcsncpy(
  847. wstrTmp,
  848. (pSessionData->AuthenticationPackage).Buffer,
  849. (pSessionData->AuthenticationPackage).Length);
  850. (usiter->second).m_chstrAuthPkg = wstrTmp;
  851. }
  852. (usiter->second).m_ulLogonType =
  853. pSessionData->LogonType;
  854. (usiter->second).i64LogonTime =
  855. *((__int64*)(&(pSessionData->LogonTime)));
  856. }
  857. }
  858. }
  859. }
  860. }
  861. }
  862. else
  863. {
  864. LogErrorMessage(L"Failed to load library SECUR32.dll");
  865. }
  866. return dwRet;
  867. }
  868. //*****************************************************************************
  869. // CSession functions
  870. //*****************************************************************************
  871. CSession::CSession(
  872. const LUID& luidSessionID)
  873. {
  874. m_luid.LowPart = luidSessionID.LowPart;
  875. m_luid.HighPart = luidSessionID.HighPart;
  876. m_ulLogonType = 0;
  877. i64LogonTime = 0;
  878. }
  879. CSession::CSession(
  880. const CSession& ses)
  881. {
  882. m_luid.LowPart = ses.m_luid.LowPart;
  883. m_luid.HighPart = ses.m_luid.HighPart;
  884. m_chstrAuthPkg = ses.m_chstrAuthPkg;
  885. m_ulLogonType = ses.m_ulLogonType;
  886. i64LogonTime = ses.i64LogonTime;
  887. m_vecProcesses.clear();
  888. for(long lPos = 0;
  889. lPos < ses.m_vecProcesses.size();
  890. lPos++)
  891. {
  892. m_vecProcesses.push_back(
  893. ses.m_vecProcesses[lPos]);
  894. }
  895. }
  896. LUID CSession::GetLUID() const
  897. {
  898. return m_luid;
  899. }
  900. __int64 CSession::GetLUIDint64() const
  901. {
  902. __int64 i64LuidSes = *((__int64*)(&m_luid));
  903. return i64LuidSes;
  904. }
  905. CHString CSession::GetAuthenticationPkg() const
  906. {
  907. return m_chstrAuthPkg;
  908. }
  909. ULONG CSession::GetLogonType() const
  910. {
  911. return m_ulLogonType;
  912. }
  913. __int64 CSession::GetLogonTime() const
  914. {
  915. return i64LogonTime;
  916. }
  917. // Functions to support enumeration of
  918. // processes associated with this session.
  919. // Returns a newly allocated CProcess* that
  920. // the caller must free.
  921. CProcess* CSession::GetFirstProcess(
  922. PROCESS_ITERATOR& pos)
  923. {
  924. CProcess* procRet = NULL;
  925. if(!m_vecProcesses.empty())
  926. {
  927. pos = m_vecProcesses.begin();
  928. procRet = new CProcess(*pos);
  929. }
  930. return procRet;
  931. }
  932. // Returns a newly allocated CProcess* that
  933. // the caller must free.
  934. CProcess* CSession::GetNextProcess(
  935. PROCESS_ITERATOR& pos)
  936. {
  937. CProcess* procRet = NULL;
  938. if(pos >= m_vecProcesses.begin() &&
  939. pos < m_vecProcesses.end())
  940. {
  941. pos++;
  942. if(pos != m_vecProcesses.end())
  943. {
  944. procRet = new CProcess(*pos);
  945. }
  946. }
  947. return procRet;
  948. }
  949. void CSession::Copy(
  950. CSession& sesCopy) const
  951. {
  952. sesCopy.m_luid.LowPart = m_luid.LowPart;
  953. sesCopy.m_luid.HighPart = m_luid.HighPart;
  954. sesCopy.m_chstrAuthPkg = m_chstrAuthPkg;
  955. sesCopy.m_ulLogonType = m_ulLogonType;
  956. sesCopy.i64LogonTime = i64LogonTime;
  957. sesCopy.m_vecProcesses.clear();
  958. for(long lPos = 0;
  959. lPos < m_vecProcesses.size();
  960. lPos++)
  961. {
  962. sesCopy.m_vecProcesses.push_back(
  963. m_vecProcesses[lPos]);
  964. }
  965. }
  966. // This function impersonates the
  967. // explorer process in the session's
  968. // process array, if it is present.
  969. // (If it isn't, impersonates the
  970. // first process in the process array.)
  971. // Returns the handle of token of the
  972. // thread we started from for easy
  973. // reversion, orINVALID_HANDLE_VALUE if
  974. // we couldn't impersonate. The caller
  975. // must close that handle.
  976. HANDLE CSession::Impersonate()
  977. {
  978. HANDLE hCurToken = INVALID_HANDLE_VALUE;
  979. // Find the explorer process...
  980. DWORD dwImpProcPID = GetImpProcPID();
  981. if(dwImpProcPID != -1L)
  982. {
  983. //
  984. // smart CloseHandle
  985. //
  986. ScopeGuard SmartCloseHandleFnc = MakeGuard ( CloseHandle, hCurToken ) ;
  987. bool fOK = false;
  988. if(::OpenThreadToken(
  989. ::GetCurrentThread(),
  990. TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE ,
  991. TRUE,
  992. &hCurToken))
  993. {
  994. SmartCloseHandle hProcess;
  995. hProcess = ::OpenProcess(
  996. PROCESS_QUERY_INFORMATION,
  997. FALSE,
  998. dwImpProcPID);
  999. if(hProcess)
  1000. {
  1001. // now open its token...
  1002. SmartCloseHandle hExplorerToken;
  1003. if(::OpenProcessToken(
  1004. hProcess,
  1005. TOKEN_READ | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE,
  1006. &hExplorerToken))
  1007. {
  1008. CProcessToken cpt ( hExplorerToken );
  1009. if ( cpt.IsValidToken () )
  1010. {
  1011. TOKEN_TYPE type;
  1012. if ( cpt.GetTokenType ( type ) )
  1013. {
  1014. if ( TokenPrimary == type )
  1015. {
  1016. CToken ct;
  1017. if ( ct.Duplicate ( cpt, FALSE ) )
  1018. {
  1019. // Set the thread token...
  1020. if(::SetThreadToken(NULL, ct.GetTokenHandle ()))
  1021. {
  1022. fOK = true;
  1023. }
  1024. }
  1025. }
  1026. else
  1027. {
  1028. // Set the thread token...
  1029. if(::SetThreadToken(NULL, cpt.GetTokenHandle ()))
  1030. {
  1031. fOK = true;
  1032. }
  1033. }
  1034. }
  1035. }
  1036. }
  1037. }
  1038. }
  1039. SmartCloseHandleFnc.Dismiss () ;
  1040. if (!fOK)
  1041. {
  1042. if(hCurToken != INVALID_HANDLE_VALUE)
  1043. {
  1044. ::CloseHandle(hCurToken);
  1045. hCurToken = INVALID_HANDLE_VALUE;
  1046. }
  1047. }
  1048. }
  1049. return hCurToken;
  1050. }
  1051. DWORD CSession::GetImpProcPID()
  1052. {
  1053. DWORD dwRet = -1L;
  1054. if(!m_vecProcesses.empty())
  1055. {
  1056. bool fFoundExplorerExe = false;
  1057. for(long m = 0;
  1058. m < m_vecProcesses.size() &&
  1059. !fFoundExplorerExe;)
  1060. {
  1061. if(m_vecProcesses[m].GetImageName().CompareNoCase(
  1062. L"explorer.exe") == 0)
  1063. {
  1064. fFoundExplorerExe = true;
  1065. break;
  1066. }
  1067. else
  1068. {
  1069. m++;
  1070. }
  1071. }
  1072. if(!fFoundExplorerExe)
  1073. {
  1074. m = 0;
  1075. }
  1076. dwRet = m_vecProcesses[m].GetPID();
  1077. }
  1078. return dwRet;
  1079. }
  1080. bool CSession::IsSessionIDValid(
  1081. LPCWSTR wstrSessionID)
  1082. {
  1083. bool fRet = true;
  1084. if(wstrSessionID != NULL &&
  1085. *wstrSessionID != L'\0')
  1086. {
  1087. for(const WCHAR* pwc = wstrSessionID;
  1088. *pwc != NULL && fRet;
  1089. pwc++)
  1090. {
  1091. fRet = iswdigit(*pwc);
  1092. }
  1093. }
  1094. else
  1095. {
  1096. fRet = false;
  1097. }
  1098. return fRet;
  1099. }
  1100. //*****************************************************************************
  1101. // CProcess functions
  1102. //*****************************************************************************
  1103. CProcess::CProcess()
  1104. : m_dwPID(0)
  1105. {
  1106. }
  1107. CProcess::CProcess(
  1108. DWORD dwPID,
  1109. LPCWSTR wstrImageName)
  1110. : m_dwPID(dwPID)
  1111. {
  1112. m_chstrImageName = wstrImageName;
  1113. }
  1114. CProcess::CProcess(
  1115. const CProcess& process)
  1116. {
  1117. m_dwPID = process.m_dwPID;
  1118. m_chstrImageName = process.m_chstrImageName;
  1119. }
  1120. CProcess::~CProcess()
  1121. {
  1122. }
  1123. DWORD CProcess::GetPID() const
  1124. {
  1125. return m_dwPID;
  1126. }
  1127. CHString CProcess::GetImageName() const
  1128. {
  1129. return m_chstrImageName;
  1130. }
  1131. void CProcess::Copy(
  1132. CProcess& out) const
  1133. {
  1134. out.m_dwPID = m_dwPID;
  1135. out.m_chstrImageName = m_chstrImageName;
  1136. }
  1137. //*****************************************************************************
  1138. // CUser functions
  1139. //*****************************************************************************
  1140. CUser::CUser(
  1141. PSID pSid)
  1142. : m_sidUser(NULL),
  1143. m_fValid(false)
  1144. {
  1145. if(::IsValidSid(pSid))
  1146. {
  1147. DWORD dwSize = ::GetLengthSid(pSid);
  1148. m_sidUser = NULL;
  1149. m_sidUser = malloc(dwSize);
  1150. if(m_sidUser == NULL)
  1151. {
  1152. throw CHeap_Exception(
  1153. CHeap_Exception::E_ALLOCATION_ERROR);
  1154. }
  1155. else
  1156. {
  1157. ::CopySid(
  1158. dwSize,
  1159. m_sidUser,
  1160. pSid);
  1161. m_fValid = true;
  1162. }
  1163. }
  1164. }
  1165. CUser::CUser(
  1166. const CUser& user)
  1167. {
  1168. DWORD dwSize = ::GetLengthSid(user.m_sidUser);
  1169. m_sidUser = malloc(dwSize);
  1170. if(m_sidUser == NULL)
  1171. {
  1172. throw CHeap_Exception(
  1173. CHeap_Exception::E_ALLOCATION_ERROR);
  1174. }
  1175. ::CopySid(
  1176. dwSize,
  1177. m_sidUser,
  1178. user.m_sidUser);
  1179. m_fValid = user.m_fValid;
  1180. }
  1181. CUser::~CUser()
  1182. {
  1183. if(m_sidUser)
  1184. {
  1185. free(m_sidUser);
  1186. m_sidUser = NULL;
  1187. }
  1188. }
  1189. bool CUser::IsValid()
  1190. {
  1191. return m_fValid;
  1192. }
  1193. void CUser::Copy(
  1194. CUser& out) const
  1195. {
  1196. if(out.m_sidUser)
  1197. {
  1198. free(out.m_sidUser);
  1199. out.m_sidUser = NULL;
  1200. }
  1201. DWORD dwSize = ::GetLengthSid(m_sidUser);
  1202. out.m_sidUser = malloc(dwSize);
  1203. if(out.m_sidUser == NULL)
  1204. {
  1205. throw CHeap_Exception(
  1206. CHeap_Exception::E_ALLOCATION_ERROR);
  1207. }
  1208. ::CopySid(
  1209. dwSize,
  1210. out.m_sidUser,
  1211. m_sidUser);
  1212. out.m_fValid = m_fValid;
  1213. }
  1214. // Implementation lifted from sid.cpp.
  1215. void CUser::GetSidString(CHString& str) const
  1216. {
  1217. ASSERT_BREAK(m_fValid);
  1218. if(m_fValid)
  1219. {
  1220. // Initialize m_strSid - human readable form of our SID
  1221. SID_IDENTIFIER_AUTHORITY *psia = NULL;
  1222. psia = ::GetSidIdentifierAuthority( m_sidUser );
  1223. // We assume that only last byte is used (authorities between 0 and 15).
  1224. // Correct this if needed.
  1225. ASSERT_BREAK( psia->Value[0] == psia->Value[1] ==
  1226. psia->Value[2] == psia->Value[3] ==
  1227. psia->Value[4] == 0 );
  1228. DWORD dwTopAuthority = psia->Value[5];
  1229. str.Format( L"S-1-%u", dwTopAuthority );
  1230. CHString strSubAuthority;
  1231. int iSubAuthorityCount = *( GetSidSubAuthorityCount( m_sidUser ) );
  1232. for ( int i = 0; i < iSubAuthorityCount; i++ ) {
  1233. DWORD dwSubAuthority = *( GetSidSubAuthority( m_sidUser, i ) );
  1234. strSubAuthority.Format( L"%u", dwSubAuthority );
  1235. str += _T("-") + strSubAuthority;
  1236. }
  1237. }
  1238. }