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.
 
 
 
 
 
 

1495 lines
39 KiB

//=============================================================================
// session.cpp -- implementation of session collection class.
//
// Copyright (c) 1998-2002 Microsoft Corporation, All Rights Reserved
//=============================================================================
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntobapi.h>
#define _WINNT_ // have what is needed from above
#pragma warning (disable: 4786)
#include "precomp.h"
#include <map>
#include <vector>
#include <comdef.h>
#include "chstring.h"
#include "session.h"
#include <ProvExce.h>
#include <AssertBreak.h>
#include <wbemcli.h>
#include <ntsecapi.h>
#ifdef _WIN32_WINNT
#define SECURITY_WIN32
#else
#define SECURITY_WIN16
#endif
#include <sspi.h>
#include "ctoken.h"
#include <autoptr.h>
#include <ScopeGuard.h>
typedef SECURITY_STATUS (SEC_ENTRY *PFN_LSA_ENUMERATE_LOGON_SESSIONS)
(
OUT PULONG LogonSessionCount,
OUT PLUID* LogonSessionList
);
typedef SECURITY_STATUS (SEC_ENTRY *PFN_LSA_GET_LOGON_SESSION_DATA)
(
IN PLUID LogonId,
OUT PSECURITY_LOGON_SESSION_DATA* ppLogonSessionData
);
typedef NTSTATUS (*PFN_LSA_FREE_RETURN_BUFFER)
(
IN PVOID Buffer
);
//*****************************************************************************
// CUserSessionCollection functions
//*****************************************************************************
CUserSessionCollection::CUserSessionCollection()
{
Refresh();
}
CUserSessionCollection::CUserSessionCollection(
const CUserSessionCollection& sescol)
{
m_usr2ses.clear();
USER_SESSION_ITERATOR sourceIter;
for(sourceIter = sescol.m_usr2ses.begin();
sourceIter != sescol.m_usr2ses.end();
sourceIter++)
{
m_usr2ses.insert(
USER_SESSION_MAP::value_type(
sourceIter->first,
sourceIter->second));
}
}
DWORD CUserSessionCollection::Refresh()
{
DWORD dwRet = ERROR_SUCCESS;
// Empty out previous contents...
m_usr2ses.clear();
dwRet = CollectSessions();
return dwRet;
}
DWORD CUserSessionCollection::CollectSessions()
{
DWORD dwRet = ERROR_SUCCESS;
std::vector<CProcess> vecProcesses;
SmartCloseHandle hProcess;
SmartCloseHandle hToken;
TOKEN_STATISTICS tokstats;
PTOKEN_USER ptokusr = NULL;
DWORD dwRetSize = 0L;
PSID psidUsr = NULL;
CHString chstrUsr;
LUID luidSes;
// Enable the debug privilege...
EnablePrivilegeOnCurrentThread(SE_DEBUG_NAME);
// Get a list of all running processes...
dwRet = GetProcessList(vecProcesses);
if(dwRet == ERROR_SUCCESS)
{
// For each member of the process list...
for(long m = 0L;
m < vecProcesses.size();
m++)
{
// open the process...
::SetLastError(ERROR_SUCCESS);
dwRet = ERROR_SUCCESS;
hProcess = ::OpenProcess(
PROCESS_QUERY_INFORMATION,
FALSE,
vecProcesses[m].GetPID());
if(hProcess == NULL)
{
dwRet = ::GetLastError();
}
// get the process token...
if(hProcess != NULL &&
dwRet == ERROR_SUCCESS)
{
::SetLastError(ERROR_SUCCESS);
dwRet = ERROR_SUCCESS;
if(!::OpenProcessToken(
hProcess,
TOKEN_QUERY,
&hToken))
{
dwRet = ::GetLastError();
}
}
// get the token statistics...
if(hToken != NULL &&
dwRet == ERROR_SUCCESS)
{
::SetLastError(ERROR_SUCCESS);
dwRet = ERROR_SUCCESS;
if(!::GetTokenInformation(
hToken,
TokenStatistics,
&tokstats,
sizeof(TOKEN_STATISTICS),
&dwRetSize))
{
dwRet = ::GetLastError();
}
}
//
// smart token user
//
wmilib::auto_buffer < BYTE > smartptokusr;
// get the token user sid...
if(dwRet == ERROR_SUCCESS)
{
// the token user struct varries
// in size depending on the size
// of the sid in the SID_AND_ATTRIBUTES
// structure, so need to allocate
// it dynamically.
if(!::GetTokenInformation(
hToken,
TokenUser,
NULL,
0L,
&dwRetSize))
{
dwRet = ::GetLastError();
}
if(dwRet == ERROR_INSUFFICIENT_BUFFER)
{
smartptokusr.reset ( new BYTE [ dwRetSize ] ) ;
ptokusr = (PTOKEN_USER) smartptokusr.get () ;
DWORD dwTmp = dwRetSize;
if(!::GetTokenInformation(
hToken,
TokenUser,
ptokusr,
dwTmp,
&dwRetSize))
{
dwRet = ::GetLastError();
}
else
{
dwRet = ERROR_SUCCESS ;
}
}
}
if(ptokusr != NULL)
{
if(dwRet == ERROR_SUCCESS)
{
psidUsr = (ptokusr->User).Sid;
// from the token statistics, get
// the TokenID LUID of the session...
luidSes.LowPart = tokstats.AuthenticationId.LowPart;
luidSes.HighPart = tokstats.AuthenticationId.HighPart;
// try to find the session of the
// process in the multimap...
USER_SESSION_ITERATOR usiter;
if(FindSessionInternal(
luidSes,
usiter))
{
// try to find the process id in the
// session's process vector...
CSession sesTmp(usiter->second);
CProcess* procTmp = NULL;
bool fFoundIt = false;
for(long z = 0L;
z < sesTmp.m_vecProcesses.size() && !fFoundIt;
z++)
{
if((DWORD)(sesTmp.m_vecProcesses[z].GetPID()) ==
vecProcesses[m].GetPID())
{
fFoundIt = true;
}
}
// If we didn't find the process in the
// session's list of processes, add it in...
if(!fFoundIt)
{
(usiter->second).m_vecProcesses.push_back(
CProcess(vecProcesses[m]));
}
}
else // no such session in the map, so add an entry
{
// Create new CSession(tokenid LUID), and
// add process to the session's process vector...
CSession sesNew(luidSes);
sesNew.m_vecProcesses.push_back(
vecProcesses[m]);
// add CUser(user sid) to map.first and the
// CSession just created to map.second...
CUser cuTmp(psidUsr);
if(cuTmp.IsValid())
{
m_usr2ses.insert(
USER_SESSION_MAP::value_type(
cuTmp,
sesNew));
}
else
{
LogErrorMessage2(
L"Token of process %d contains an invalid sid",
vecProcesses[m].GetPID());
}
}
}
}
} // next process
}
// There may have been sessions not associated
// with any processes. To get these, we will
// use LSA.
CollectNoProcessesSessions();
return dwRet;
}
void CUserSessionCollection::Copy(
CUserSessionCollection& out) const
{
out.m_usr2ses.clear();
USER_SESSION_ITERATOR meIter;
for(meIter = m_usr2ses.begin();
meIter != m_usr2ses.end();
meIter++)
{
out.m_usr2ses.insert(
USER_SESSION_MAP::value_type(
meIter->first,
meIter->second));
}
}
// Support enumeration of users. Returns
// a newly allocated copy of what was in
// the map (caller must free).
CUser* CUserSessionCollection::GetFirstUser(
USER_SESSION_ITERATOR& pos)
{
CUser* cusrRet = NULL;
if(!m_usr2ses.empty())
{
pos = m_usr2ses.begin();
cusrRet = new CUser(pos->first);
}
return cusrRet;
}
// Returns a newly allocated CUser*, which
// the caller must free.
CUser* CUserSessionCollection::GetNextUser(
USER_SESSION_ITERATOR& pos)
{
// Users are the non-unique part of
// the map, so we need to go through
// the map until the next user entry
// comes up.
CUser* usrRet = NULL;
while(pos != m_usr2ses.end())
{
CHString chstrSidCur;
pos->first.GetSidString(chstrSidCur);
pos++;
if(pos != m_usr2ses.end())
{
CHString chstrSidNext;
pos->first.GetSidString(chstrSidNext);
// Return the first instance where
// the next user is different from
// the current one.
if(chstrSidNext.CompareNoCase(chstrSidCur) != 0)
{
usrRet = new CUser(pos->first);
break;
}
}
}
return usrRet;
}
// Support enumeration of sessions
// belonging to a particular user.
CSession* CUserSessionCollection::GetFirstSessionOfUser(
CUser& usr,
USER_SESSION_ITERATOR& pos)
{
CSession* csesRet = NULL;
if(!m_usr2ses.empty())
{
pos = m_usr2ses.find(usr);
if(pos != m_usr2ses.end())
{
csesRet = new CSession(pos->second);
}
}
return csesRet;
}
CSession* CUserSessionCollection::GetNextSessionOfUser(
USER_SESSION_ITERATOR& pos)
{
// Sessions are the unique part of
// the map, so we just need to get
// the next one as long as pos.first
// matches usr...
CSession* sesRet = NULL;
if(pos != m_usr2ses.end())
{
CHString chstrUsr1;
CHString chstrUsr2;
(pos->first).GetSidString(chstrUsr1);
pos++;
if(pos != m_usr2ses.end())
{
(pos->first).GetSidString(chstrUsr2);
if(chstrUsr1.CompareNoCase(chstrUsr2) == 0)
{
sesRet = new CSession(pos->second);
}
}
}
return sesRet;
}
// Support enumeration of all sessions. Returns a
// newly allocated CSession*, which the caller
// must free.
CSession* CUserSessionCollection::GetFirstSession(
USER_SESSION_ITERATOR& pos)
{
CSession* csesRet = NULL;
if(!m_usr2ses.empty())
{
pos = m_usr2ses.begin();
csesRet = new CSession(pos->second);
}
return csesRet;
}
// Returns a newly allocated CSession* that the
// caller must free.
CSession* CUserSessionCollection::GetNextSession(
USER_SESSION_ITERATOR& pos)
{
// Sessions are the unique part of
// the map, so we just need to get
// the next one...
CSession* sesRet = NULL;
if(pos != m_usr2ses.end())
{
pos++;
if(pos != m_usr2ses.end())
{
sesRet = new CSession(pos->second);
}
}
return sesRet;
}
// Support finding a particular session.
// This internal version hands back an iterator
// on our member map that points to the found
// instance if found (when the function returns
// true. If the function returns
// false, the iterator points to the end of our
// map.
bool CUserSessionCollection::FindSessionInternal(
LUID& luidSes,
USER_SESSION_ITERATOR& usiOut)
{
bool fFoundIt = false;
for(usiOut = m_usr2ses.begin();
usiOut != m_usr2ses.end();
usiOut++)
{
LUID luidTmp = (usiOut->second).GetLUID();
if(luidTmp.HighPart == luidSes.HighPart &&
luidTmp.LowPart == luidSes.LowPart)
{
fFoundIt = true;
break;
}
}
return fFoundIt;
}
// Support finding a particular session - external
// callers can call this one, and are given a new
// CSession* they can play with.
CSession* CUserSessionCollection::FindSession(
LUID& luidSes)
{
CSession* psesRet = NULL;
USER_SESSION_ITERATOR pos;
if(FindSessionInternal(
luidSes,
pos))
{
psesRet = new CSession(pos->second);
}
return psesRet;
}
CSession* CUserSessionCollection::FindSession(
__int64 i64luidSes)
{
LUID luidSes = *((LUID*)(&i64luidSes));
return FindSession(luidSes);
}
// Support enumeration of processes
// belonging to a particular user. Returns
// newly allocated CProcess* which the caller
// must free.
CProcess* CUserSessionCollection::GetFirstProcessOfUser(
CUser& usr,
USER_SESSION_PROCESS_ITERATOR& pos)
{
CProcess* cprocRet = NULL;
CHString chstrUsrSidStr;
CHString chstrTmp;
if(!m_usr2ses.empty())
{
usr.GetSidString(chstrUsrSidStr);
pos.usIter = m_usr2ses.find(usr);
while(pos.usIter != m_usr2ses.end())
{
// Get the sid string of the user we
// are at and see whether the strings
// are the same (e.g., whether this is a
// session associated with the specified
// user)...
(pos.usIter)->first.GetSidString(chstrTmp);
if(chstrUsrSidStr.CompareNoCase(chstrTmp) == 0)
{
// Now check that the session of the user
// we are on has processes...
if(!(((pos.usIter)->second).m_vecProcesses.empty()))
{
pos.procIter =
((pos.usIter)->second).m_vecProcesses.begin();
cprocRet = new CProcess(*(pos.procIter));
}
else
{
// the session for this user has
// no processes, so go to the next
// session...
(pos.usIter)++;
}
}
}
}
return cprocRet;
}
// Returns a newly allocated CProcess* that the
// caller must free.
CProcess* CUserSessionCollection::GetNextProcessOfUser(
USER_SESSION_PROCESS_ITERATOR& pos)
{
CProcess* cprocRet = NULL;
CHString chstrCurUsr;
CHString chstrNxtSesUsr;
if(pos.usIter != m_usr2ses.end())
{
(pos.usIter)->first.GetSidString(chstrCurUsr);
while(pos.usIter != m_usr2ses.end())
{
// First try to get the next process
// within the current session. If we
// were at the end of the list of processes
// for the current session, go to the
// next session...
(pos.procIter)++;
// Of course, if we have moved on
// to a different user, then stop.
(pos.usIter)->first.GetSidString(chstrNxtSesUsr);
if(chstrCurUsr.CompareNoCase(chstrNxtSesUsr) == 0)
{
if(pos.procIter ==
((pos.usIter)->second).m_vecProcesses.end())
{
(pos.usIter)++;
}
else
{
cprocRet = new CProcess(*(pos.procIter));
}
}
}
}
return cprocRet;
}
// Support enumeration of all processes. Returns
// newly allocated CProcess* which the caller
// must free.
CProcess* CUserSessionCollection::GetFirstProcess(
USER_SESSION_PROCESS_ITERATOR& pos)
{
CProcess* cprocRet = NULL;
if(!m_usr2ses.empty())
{
pos.usIter = m_usr2ses.begin();
while(pos.usIter != m_usr2ses.end())
{
if(!(((pos.usIter)->second).m_vecProcesses.empty()))
{
pos.procIter =
((pos.usIter)->second).m_vecProcesses.begin();
cprocRet = new CProcess(*(pos.procIter));
}
else
{
(pos.usIter)++;
}
}
}
return cprocRet;
}
// Returns a newly allocated CProcess* that the
// caller must free.
CProcess* CUserSessionCollection::GetNextProcess(
USER_SESSION_PROCESS_ITERATOR& pos)
{
CProcess* cprocRet = NULL;
while(pos.usIter != m_usr2ses.end())
{
// First try to get the next process
// within the current session. If we
// were at the end of the list of processes
// for the current session, go to the
// next session...
(pos.procIter)++;
if(pos.procIter ==
((pos.usIter)->second).m_vecProcesses.end())
{
(pos.usIter)++;
}
else
{
cprocRet = new CProcess(*(pos.procIter));
}
}
return cprocRet;
}
// This helper enumerates the current set of processes
// and ads each process id as a DWORD in the vector.
DWORD CUserSessionCollection::GetProcessList( std::vector<CProcess>& vecProcesses ) const
{
DWORD dwRet = ERROR_SUCCESS;
// First, load up ntdll...
HMODULE hLib = NULL;
PFN_NT_QUERY_SYSTEM_INFORMATION pfnNtQuerySystemInformation = NULL;
hLib = LoadLibraryW(L"NTDLL.DLL");
if(hLib != NULL)
{
//
// auto FreeLibrary
//
ON_BLOCK_EXIT ( FreeLibrary, hLib ) ;
// Get proc address of NtQuerySystemInformation...
pfnNtQuerySystemInformation = (PFN_NT_QUERY_SYSTEM_INFORMATION)
GetProcAddress(
hLib,
"NtQuerySystemInformation");
if(pfnNtQuerySystemInformation != NULL)
{
// Ready to rock. Enable debug priv...
EnablePrivilegeOnCurrentThread(SE_DEBUG_NAME);
DWORD dwProcessInformationSize = 0;
SYSTEM_PROCESS_INFORMATION* ProcessInformation = NULL;
//
// smart ProcessInformation
//
wmilib::auto_buffer < BYTE > SmartProcessInformation;
// Get the process information...
BOOL fRetry = TRUE;
while(fRetry)
{
dwRet = pfnNtQuerySystemInformation(
SystemProcessInformation,
ProcessInformation,
dwProcessInformationSize,
NULL);
if(dwRet == STATUS_INFO_LENGTH_MISMATCH)
{
dwProcessInformationSize += 32768;
SmartProcessInformation.reset ( new BYTE [ dwProcessInformationSize ] );
ProcessInformation = (SYSTEM_PROCESS_INFORMATION*)SmartProcessInformation.get () ;
}
else
{
fRetry = FALSE;
}
}
// If we got the process information, process it...
if(ProcessInformation != NULL &&
dwRet == ERROR_SUCCESS)
{
SYSTEM_PROCESS_INFORMATION* CurrentInformation = NULL;
DWORD dwNextOffset;
CurrentInformation = ProcessInformation;
bool fContinue = true;
while(CurrentInformation != NULL &&
fContinue)
{
{
CProcess cptmp(
HandleToUlong(CurrentInformation->UniqueProcessId),
(CurrentInformation->ImageName).Buffer);
vecProcesses.push_back(cptmp);
}
dwNextOffset = CurrentInformation->NextEntryOffset;
if(dwNextOffset)
{
CurrentInformation = (SYSTEM_PROCESS_INFORMATION*)
(((BYTE*) CurrentInformation) + dwNextOffset);
}
else
{
fContinue = false;
}
}
}
}
}
else
{
LogErrorMessage(L"Failed to load library ntdll.dll");
}
return dwRet;
}
// Implementation lifted from dllutils.cpp.
DWORD CUserSessionCollection::EnablePrivilegeOnCurrentThread(
LPCTSTR szPriv) const
{
SmartCloseHandle hToken = NULL;
TOKEN_PRIVILEGES tkp;
BOOL bLookup = FALSE;
DWORD dwLastError = ERROR_SUCCESS;
// Try to open the thread token.
if (::OpenThreadToken(
GetCurrentThread(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
FALSE,
&hToken))
{
{
bLookup = ::LookupPrivilegeValue(
NULL,
szPriv,
&tkp.Privileges[0].Luid);
}
if (bLookup)
{
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Clear the last error.
SetLastError(0);
// Turn it on
::AdjustTokenPrivileges(
hToken,
FALSE,
&tkp,
0,
(PTOKEN_PRIVILEGES) NULL,
0);
dwLastError = GetLastError();
}
}
else
{
dwLastError = ::GetLastError();
}
// We have to check GetLastError() because
// AdjustTokenPrivileges lies about
// its success but GetLastError() doesn't.
return dwLastError;
}
bool CUserSessionCollection::IsSessionMapped(
LUID& luidSes)
{
bool fRet = false;
USER_SESSION_ITERATOR usiter;
usiter = m_usr2ses.begin();
for(usiter = m_usr2ses.begin();
usiter != m_usr2ses.end() && !fRet;
usiter++)
{
LUID luidTmp = (usiter->second).GetLUID();
if(luidTmp.HighPart == luidSes.HighPart &&
luidTmp.LowPart == luidSes.LowPart)
{
fRet = true;
}
}
return fRet;
}
bool CUserSessionCollection::IsSessionMapped(
__int64 i64luidSes)
{
LUID luidSes = *((LUID*)(&i64luidSes));
return IsSessionMapped(luidSes);
}
// Collects sessions that have no associated
// process. Uses LSA to enumerate sessions,
// then checks to see if we have each session
// already. If we don't, adds it to our map.
DWORD CUserSessionCollection::CollectNoProcessesSessions()
{
DWORD dwRet = ERROR_SUCCESS;
ULONG ulLogonSessionCount = 0L;
PLUID pluidLogonSessions = NULL;
HMODULE hLib = NULL;
PFN_LSA_ENUMERATE_LOGON_SESSIONS pfnEnumLogonSessions = NULL;
PFN_LSA_GET_LOGON_SESSION_DATA pfnGetLogonSessionData = NULL;
PFN_LSA_FREE_RETURN_BUFFER pfnLsaFreeReturnBuffer = NULL;
// Doing a load library here rather than using the
// resource manager, as SECURITYAPI.CPP defines us
// to point to SECURITY.DLL, not SECUR32.DLL for the
// W2K case.
hLib = ::LoadLibraryW(L"SECUR32.DLL");
if(hLib)
{
//
// auto FreeLibrary
//
ON_BLOCK_EXIT ( FreeLibrary, hLib ) ;
pfnEnumLogonSessions =
(PFN_LSA_ENUMERATE_LOGON_SESSIONS) ::GetProcAddress(
hLib,
"LsaEnumerateLogonSessions");
pfnGetLogonSessionData =
(PFN_LSA_GET_LOGON_SESSION_DATA) ::GetProcAddress(
hLib,
"LsaGetLogonSessionData");
pfnLsaFreeReturnBuffer =
(PFN_LSA_FREE_RETURN_BUFFER) ::GetProcAddress(
hLib,
"LsaFreeReturnBuffer");
if(pfnEnumLogonSessions &&
pfnGetLogonSessionData &&
pfnLsaFreeReturnBuffer)
{
dwRet = pfnEnumLogonSessions(
&ulLogonSessionCount,
&pluidLogonSessions);
if(dwRet == ERROR_SUCCESS &&
pluidLogonSessions)
{
//
// auto destructor for logon session
//
ON_BLOCK_EXIT ( pfnLsaFreeReturnBuffer, pluidLogonSessions ) ;
for(ULONG u = 0L;
u < ulLogonSessionCount && dwRet == ERROR_SUCCESS;
u++)
{
PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
dwRet = pfnGetLogonSessionData(
&pluidLogonSessions[u],
&pSessionData);
if(dwRet == ERROR_SUCCESS &&
pSessionData)
{
//
// smart session data
//
ON_BLOCK_EXIT ( pfnLsaFreeReturnBuffer, pSessionData ) ;
// See if we have the session already...
if(!IsSessionMapped(pSessionData->LogonId))
{
// and if not, add it to the map.
CSession sesNew(pSessionData->LogonId);
CUser cuTmp(pSessionData->Sid);
CHString chstrTmp;
if(cuTmp.IsValid())
{
cuTmp.GetSidString(chstrTmp);
m_usr2ses.insert(
USER_SESSION_MAP::value_type(
cuTmp,
sesNew));
}
else
{
LUID luidTmp = sesNew.GetLUID();
LogMessage3(
L"GetLogonSessionData returned logon data for session "
L"luid %d (highpart) %u (lowpart) containing an invalid SID",
luidTmp.HighPart,
luidTmp.LowPart);
}
}
// While we are here, add in various
// session properties lsa has been kind
// enough to provide for us.
USER_SESSION_ITERATOR usiter;
usiter = m_usr2ses.begin();
bool fFound = false;
while(usiter != m_usr2ses.end() &&
!fFound)
{
LUID luidTmp = pSessionData->LogonId;
__int64 i64Tmp = *((__int64*)(&luidTmp));
if((usiter->second).GetLUIDint64() ==
i64Tmp)
{
fFound = true;
}
else
{
usiter++;
}
}
if(fFound)
{
WCHAR wstrTmp[_MAX_PATH] = { '\0' };
if((pSessionData->AuthenticationPackage).Length < (_MAX_PATH - 1))
{
wcsncpy(
wstrTmp,
(pSessionData->AuthenticationPackage).Buffer,
(pSessionData->AuthenticationPackage).Length);
(usiter->second).m_chstrAuthPkg = wstrTmp;
}
(usiter->second).m_ulLogonType =
pSessionData->LogonType;
(usiter->second).i64LogonTime =
*((__int64*)(&(pSessionData->LogonTime)));
}
}
}
}
}
}
else
{
LogErrorMessage(L"Failed to load library SECUR32.dll");
}
return dwRet;
}
//*****************************************************************************
// CSession functions
//*****************************************************************************
CSession::CSession(
const LUID& luidSessionID)
{
m_luid.LowPart = luidSessionID.LowPart;
m_luid.HighPart = luidSessionID.HighPart;
m_ulLogonType = 0;
i64LogonTime = 0;
}
CSession::CSession(
const CSession& ses)
{
m_luid.LowPart = ses.m_luid.LowPart;
m_luid.HighPart = ses.m_luid.HighPart;
m_chstrAuthPkg = ses.m_chstrAuthPkg;
m_ulLogonType = ses.m_ulLogonType;
i64LogonTime = ses.i64LogonTime;
m_vecProcesses.clear();
for(long lPos = 0;
lPos < ses.m_vecProcesses.size();
lPos++)
{
m_vecProcesses.push_back(
ses.m_vecProcesses[lPos]);
}
}
LUID CSession::GetLUID() const
{
return m_luid;
}
__int64 CSession::GetLUIDint64() const
{
__int64 i64LuidSes = *((__int64*)(&m_luid));
return i64LuidSes;
}
CHString CSession::GetAuthenticationPkg() const
{
return m_chstrAuthPkg;
}
ULONG CSession::GetLogonType() const
{
return m_ulLogonType;
}
__int64 CSession::GetLogonTime() const
{
return i64LogonTime;
}
// Functions to support enumeration of
// processes associated with this session.
// Returns a newly allocated CProcess* that
// the caller must free.
CProcess* CSession::GetFirstProcess(
PROCESS_ITERATOR& pos)
{
CProcess* procRet = NULL;
if(!m_vecProcesses.empty())
{
pos = m_vecProcesses.begin();
procRet = new CProcess(*pos);
}
return procRet;
}
// Returns a newly allocated CProcess* that
// the caller must free.
CProcess* CSession::GetNextProcess(
PROCESS_ITERATOR& pos)
{
CProcess* procRet = NULL;
if(pos >= m_vecProcesses.begin() &&
pos < m_vecProcesses.end())
{
pos++;
if(pos != m_vecProcesses.end())
{
procRet = new CProcess(*pos);
}
}
return procRet;
}
void CSession::Copy(
CSession& sesCopy) const
{
sesCopy.m_luid.LowPart = m_luid.LowPart;
sesCopy.m_luid.HighPart = m_luid.HighPart;
sesCopy.m_chstrAuthPkg = m_chstrAuthPkg;
sesCopy.m_ulLogonType = m_ulLogonType;
sesCopy.i64LogonTime = i64LogonTime;
sesCopy.m_vecProcesses.clear();
for(long lPos = 0;
lPos < m_vecProcesses.size();
lPos++)
{
sesCopy.m_vecProcesses.push_back(
m_vecProcesses[lPos]);
}
}
// This function impersonates the
// explorer process in the session's
// process array, if it is present.
// (If it isn't, impersonates the
// first process in the process array.)
// Returns the handle of token of the
// thread we started from for easy
// reversion, orINVALID_HANDLE_VALUE if
// we couldn't impersonate. The caller
// must close that handle.
HANDLE CSession::Impersonate()
{
HANDLE hCurToken = INVALID_HANDLE_VALUE;
// Find the explorer process...
DWORD dwImpProcPID = GetImpProcPID();
if(dwImpProcPID != -1L)
{
//
// smart CloseHandle
//
ScopeGuard SmartCloseHandleFnc = MakeGuard ( CloseHandle, hCurToken ) ;
bool fOK = false;
if(::OpenThreadToken(
::GetCurrentThread(),
TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE ,
TRUE,
&hCurToken))
{
SmartCloseHandle hProcess;
hProcess = ::OpenProcess(
PROCESS_QUERY_INFORMATION,
FALSE,
dwImpProcPID);
if(hProcess)
{
// now open its token...
SmartCloseHandle hExplorerToken;
if(::OpenProcessToken(
hProcess,
TOKEN_READ | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE,
&hExplorerToken))
{
CProcessToken cpt ( hExplorerToken );
if ( cpt.IsValidToken () )
{
TOKEN_TYPE type;
if ( cpt.GetTokenType ( type ) )
{
if ( TokenPrimary == type )
{
CToken ct;
if ( ct.Duplicate ( cpt, FALSE ) )
{
// Set the thread token...
if(::SetThreadToken(NULL, ct.GetTokenHandle ()))
{
fOK = true;
}
}
}
else
{
// Set the thread token...
if(::SetThreadToken(NULL, cpt.GetTokenHandle ()))
{
fOK = true;
}
}
}
}
}
}
}
SmartCloseHandleFnc.Dismiss () ;
if (!fOK)
{
if(hCurToken != INVALID_HANDLE_VALUE)
{
::CloseHandle(hCurToken);
hCurToken = INVALID_HANDLE_VALUE;
}
}
}
return hCurToken;
}
DWORD CSession::GetImpProcPID()
{
DWORD dwRet = -1L;
if(!m_vecProcesses.empty())
{
bool fFoundExplorerExe = false;
for(long m = 0;
m < m_vecProcesses.size() &&
!fFoundExplorerExe;)
{
if(m_vecProcesses[m].GetImageName().CompareNoCase(
L"explorer.exe") == 0)
{
fFoundExplorerExe = true;
break;
}
else
{
m++;
}
}
if(!fFoundExplorerExe)
{
m = 0;
}
dwRet = m_vecProcesses[m].GetPID();
}
return dwRet;
}
bool CSession::IsSessionIDValid(
LPCWSTR wstrSessionID)
{
bool fRet = true;
if(wstrSessionID != NULL &&
*wstrSessionID != L'\0')
{
for(const WCHAR* pwc = wstrSessionID;
*pwc != NULL && fRet;
pwc++)
{
fRet = iswdigit(*pwc);
}
}
else
{
fRet = false;
}
return fRet;
}
//*****************************************************************************
// CProcess functions
//*****************************************************************************
CProcess::CProcess()
: m_dwPID(0)
{
}
CProcess::CProcess(
DWORD dwPID,
LPCWSTR wstrImageName)
: m_dwPID(dwPID)
{
m_chstrImageName = wstrImageName;
}
CProcess::CProcess(
const CProcess& process)
{
m_dwPID = process.m_dwPID;
m_chstrImageName = process.m_chstrImageName;
}
CProcess::~CProcess()
{
}
DWORD CProcess::GetPID() const
{
return m_dwPID;
}
CHString CProcess::GetImageName() const
{
return m_chstrImageName;
}
void CProcess::Copy(
CProcess& out) const
{
out.m_dwPID = m_dwPID;
out.m_chstrImageName = m_chstrImageName;
}
//*****************************************************************************
// CUser functions
//*****************************************************************************
CUser::CUser(
PSID pSid)
: m_sidUser(NULL),
m_fValid(false)
{
if(::IsValidSid(pSid))
{
DWORD dwSize = ::GetLengthSid(pSid);
m_sidUser = NULL;
m_sidUser = malloc(dwSize);
if(m_sidUser == NULL)
{
throw CHeap_Exception(
CHeap_Exception::E_ALLOCATION_ERROR);
}
else
{
::CopySid(
dwSize,
m_sidUser,
pSid);
m_fValid = true;
}
}
}
CUser::CUser(
const CUser& user)
{
DWORD dwSize = ::GetLengthSid(user.m_sidUser);
m_sidUser = malloc(dwSize);
if(m_sidUser == NULL)
{
throw CHeap_Exception(
CHeap_Exception::E_ALLOCATION_ERROR);
}
::CopySid(
dwSize,
m_sidUser,
user.m_sidUser);
m_fValid = user.m_fValid;
}
CUser::~CUser()
{
if(m_sidUser)
{
free(m_sidUser);
m_sidUser = NULL;
}
}
bool CUser::IsValid()
{
return m_fValid;
}
void CUser::Copy(
CUser& out) const
{
if(out.m_sidUser)
{
free(out.m_sidUser);
out.m_sidUser = NULL;
}
DWORD dwSize = ::GetLengthSid(m_sidUser);
out.m_sidUser = malloc(dwSize);
if(out.m_sidUser == NULL)
{
throw CHeap_Exception(
CHeap_Exception::E_ALLOCATION_ERROR);
}
::CopySid(
dwSize,
out.m_sidUser,
m_sidUser);
out.m_fValid = m_fValid;
}
// Implementation lifted from sid.cpp.
void CUser::GetSidString(CHString& str) const
{
ASSERT_BREAK(m_fValid);
if(m_fValid)
{
// Initialize m_strSid - human readable form of our SID
SID_IDENTIFIER_AUTHORITY *psia = NULL;
psia = ::GetSidIdentifierAuthority( m_sidUser );
// We assume that only last byte is used (authorities between 0 and 15).
// Correct this if needed.
ASSERT_BREAK( psia->Value[0] == psia->Value[1] ==
psia->Value[2] == psia->Value[3] ==
psia->Value[4] == 0 );
DWORD dwTopAuthority = psia->Value[5];
str.Format( L"S-1-%u", dwTopAuthority );
CHString strSubAuthority;
int iSubAuthorityCount = *( GetSidSubAuthorityCount( m_sidUser ) );
for ( int i = 0; i < iSubAuthorityCount; i++ ) {
DWORD dwSubAuthority = *( GetSidSubAuthority( m_sidUser, i ) );
strSubAuthority.Format( L"%u", dwSubAuthority );
str += _T("-") + strSubAuthority;
}
}
}