Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the current number of interactive user sessions in Windows?

I'm writing a Windows service that needs to know whether there are any users currently logged-on in the machine.

So far I've tried Win32_LogonSession (WMI), and LsaEnumerateLogonSessions/LsaGetLogonSessionData (secur32.dll).

Both work, and seem to return the same data, but they are too slow to update when a user log off:

  • When the system starts, they return "0 interactive users". (OK)
  • When I log on, they return "1 interactive user". (OK)
  • But then when I log off, the number of users is kept at 1. After a new log-on, the number is 2, and so on.

Thus Win32_LogonSession nor LsaEnumerateLogonSessions are good enough. The service needs to know within 5 minutes after the last interactive user leaves.

Not even SysInternals' LogonSessions.exe gives up-to-date answers.
Also, the answer cannot be "monitor logon and logoff events and have a counter variable", because the service can be started at any time.

like image 876
tiago2014 Avatar asked Oct 23 '25 14:10

tiago2014


2 Answers

I ended up with the following approach: count the number of interactive sessions which have at least one process running.

1) Get the logon session id for each interactive session.

  • LsaEnumerateLogonSessions (secur32.dll)
  • LsaGetLogonSessionData (secur32.dll)
  • sessionData.LogonType = SECURITY_LOGON_TYPE.Interactive or sessionData.LogonType = SECURITY_LOGON_TYPE.RemoteInteractive
  • sessionData.LoginID <- Keep this value in a LUID set.
  • LsaFreeReturnBuffer (secur32.dll)

2) Get the logon session id for each running process.

[First we need to enable the SeDebugPrivilege to the current application.]

  • GetCurrentProcess (kernel32.dll)
  • OpenProcessToken TOKEN_ADJUST_PRIVILEGES (advapi32.dll)
  • LookupPrivilegeValue SE_DEBUG_NAME (advapi32.dll)
  • AdjustTokenPrivileges (advapi32.dll)
  • CloseHandle (kernel32.dll)

[Then retrieve the data we want.]

  • EnumProcesses (psapi.dll)
  • OpenProcess PROCESS_QUERY_INFORMATION (kernel32.dll)
  • OpenProcessToken TOKEN_QUERY (advapi32.dll)
  • GetTokenInformation TOKEN_INFORMATION_CLASS.TokenStatistics (advapi32.dll)
  • accessTokenStatistics.AuthenticationId <- Keep this value in a LUID set.
  • CloseHandle (kernel32.dll)

3) Sets intersection cardinality

interactiveSessionsCount = | { sessionData.LoginID } ∩ { accessTokenStatistics.AuthenticationId } |

Obs: sessionData.LoginID and accessTokenStatistics.AuthenticationId are both of type LUID.

like image 166
tiago2014 Avatar answered Oct 26 '25 04:10

tiago2014


WTSEnumerateSessionsA + WTSQuerySessionInformationA work better with detecting active/interactive sessions.

like image 32
AntonK Avatar answered Oct 26 '25 06:10

AntonK



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!