LsaEnumerateLogonSessions error - c++

I have a Windows service which starts another application using CreateProcess. Thus, the application runs with SYSTEM privileges. This application calls LsaEnumerateLogonSessions, which returns the error code 8 (Not enough storage is available to process this command.). The service and the application are run under Windows 7 x64.
ULONG luLogonSessionCount = 0;
LUID *pLogonSessionList = NULL;
NTSTATUS lNtStatus = LsaEnumerateLogonSessions(
&luLogonSessionCount, &pLogonSessionList );
LsaNtStatusToWinError( lNtStatus ) returns 8. Does anyone know the cause of this?
Thanks in advance!

Most services nowadays run under a service account, for security reasons. Check that your service has adequate permissions. What is the actual NTSTATUS result?

Related

Crashing when calling QTcpSocket::setSocketDescriptor()

my project using QTcpSocket and the function setSocketDescriptor(). The code is very normal
QTcpSocket *socket = new QTcpSocket();
socket->setSocketDescriptor(this->m_socketDescriptor);
This coding worked fine most of the time until I ran a performance testing on Windows Server 2016, the crash occurred. I debugging with the crash dump, here is the log
0000004f`ad1ff4e0 : ucrtbase!abort+0x4e
00000000`6ed19790 : Qt5Core!qt_logging_to_console+0x15a
000001b7`79015508 : Qt5Core!QMessageLogger::fatal+0x6d
0000004f`ad1ff0f0 : Qt5Core!QEventDispatcherWin32::installMessageHook+0xc0
00000000`00000000 : Qt5Core!QEventDispatcherWin32::createInternalHwnd+0xf3
000001b7`785b0000 : Qt5Core!QEventDispatcherWin32::registerSocketNotifier+0x13e
000001b7`7ad57580 : Qt5Core!QSocketNotifier::QSocketNotifier+0xf9
00000000`00000001 : Qt5Network!QLocalSocket::socketDescriptor+0x4cf7
00000000`00000000 : Qt5Network!QAbstractSocket::setSocketDescriptor+0x256
In the stderr log, I see those logs
CreateWindow() for QEventDispatcherWin32 internal window failed (Not enough storage is available to process this command.)
Qt: INTERNAL ERROR: failed to install GetMessage hook: 8, Not enough storage is available to process this command.
Here is the function, where the code was stopped on the Qt codebase
void QEventDispatcherWin32::installMessageHook()
{
Q_D(QEventDispatcherWin32);
if (d->getMessageHook)
return;
// setup GetMessage hook needed to drive our posted events
d->getMessageHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC) qt_GetMessageHook, NULL, GetCurrentThreadId());
if (Q_UNLIKELY(!d->getMessageHook)) {
int errorCode = GetLastError();
qFatal("Qt: INTERNAL ERROR: failed to install GetMessage hook: %d, %s",
errorCode, qPrintable(qt_error_string(errorCode)));
}
}
I did research and the error Not enough storage is available to process this command. maybe the OS (Windows) does not have enough resources to process this function (SetWindowsHookEx) and failed to create a hook, and then Qt fire a fatal signal, finally my app is killed.
I tested this on Windows Server 2019, the app is working fine, no crashes appear.
I just want to know more about the meaning of the error message (stderr) cause I don't really know what is "Not enough storage"? I think it is maybe the limit or bug of the Windows Server 2016? If yes, is there any way to overcome this issue on Windows Server 2016?
The error ‘Not enough storage is available to process this command’ usually occurs in Windows servers when the registry value is set incorrectly or after a recent reset or reinstallations, the configurations are not set correctly.
Below is verified procedure for this issue:
Click on Start > Run > regedit & press Enter
Find this key name HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\LanmanServer\Parameters
Locate IRPStackSize
If this value does not exist Right Click on Parameters key and Click on New > Dword Value and type in IRPStackSize under the name.
The name of the value must be exactly (combination of uppercase and lowercase letters) the same as what I have above.
Right Click on the IRPStackSize and click on Modify
Select Decimal enter a value higher than 15(Maximum Value is 50 decimal) and Click Ok
You can close the registry editor and restart your computer.
Reference
After researching for a few days I finally can configure the Windows Server 2016 setting (registry) to prevent the crash.
So basically it is a limitation of the OS itself, it is called desktop heap limitation.
https://learn.microsoft.com/en-us/troubleshoot/windows-server/performance/desktop-heap-limitation-out-of-memory
(The funny thing is the error message is Not enough storage is available to process this command but the real problem came to desktop heap limitation. )
So for the solution, flowing the steps in this link: https://learn.microsoft.com/en-us/troubleshoot/system-center/orchestrator/increase-maximum-number-concurrent-policy-instances
I increased the 3rd parameter of SharedSection to 2048 and it fix the issue.
Summary steps:
Desktop Heap for the non-interactive desktops is identified by the third parameter of the SharedSection= segment of the following registry value:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SubSystems\Windows
The default data for this registry value will look something like the following:
%SystemRoot%\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,3072,512 Windows=On SubSystemType=Windows ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=winsrv:ConServerDllInitialization,2 ProfileControl=Off MaxRequestThreads=16
The value to be entered into the Third Parameter of the SharedSection= segment should be based on the calculation of:
(number of desired concurrent policies) * 10 = (third parameter value)
Example: If it's desired to have 200 concurrent policy instances, then 200 * 10 = 2000, rounding up to a nice memory number gives you 2048as the third parameter resulting in the following update to be made to the registry value:
SharedSection=1024,3072,2048

OpenProcessToken fails with ERROR_ACCESS_DENIED from a local system service

Let me explain my situation first. The issue I describe below comes from an end-user's machine, and all I have to work with is just a copy of the Windows Event Log. I cannot access the machine itself to run any debugging tests.
Now the issue. I have a service application that I create as such:
SC_HANDLE hScService = CreateService(hScManager,
L"MyServiceID",
L"My Service Name",
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
SrvcPath,
NULL, NULL, NULL, NULL, _T(""));
The service process later has its SE_DEBUG_NAME privilege set using the AdjustTokenPrivileges API.
Later on I have a method that enumerates running processes and later gets processes LUIDs, using a code as such:
//'pProcIDs' = list of process IDs obtained from EnumProcesses()
for(UINT i = 0; i < nNumProc; i++)
{
DWORD dwProcID = pProcIDs[i];
//Skip obvious system processes
if(dwProcID != 0 &&
dwProcID != 4)
{
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwProcID);
if(hProcess)
{
HANDLE hTokenHandle;
if(::OpenProcessToken(hProcess, TOKEN_QUERY, &hTokenHandle))
{
TOKEN_STATISTICS ts;
DWORD dwcbSz = 0;
if(::GetTokenInformation(hTokenHandle, TokenStatistics, &ts, sizeof(ts), &dwcbSz))
{
//And so on...
}
else
{
//Handle error here
}
::CloseHandle(hTokenHandle);
}
else
{
//***Here's where I get my error in question***
}
::CloseHandle(hProcess);
}
else
{
//Handle error here
}
}
}
When I run the code above on my own development computers, it runs just fine. Note that those computers run "stock" copies of the OS without any AVP or other third-party software installed.
The event log copy I received from a customer running Windows 7 Professional machine (that is a member of an Active Directory domain) has 3 processes that return ERROR_ACCESS_DENIED when I call OpenProcessToken on them from the code above. Their PIDs are just regular values, such as 1824, 2760, 5024 (that obviously change after a reboot.)
Does anyone have any idea why it happens? Do I need to set additional privileges for my service?
PS. From the event log I can tell that the workstation in question has some Symantec Antivirus product installed, judging by this line:
New virus definition file loaded. Version: 140217066.
Symantec antivirus software (as well as that of many other security software vendors) may attempt to prevent tampering with their processes by un-authorized actors. Acquiring the process token for one of their processes just might qualify.
That said, you can quickly verify that the PIDs in question are in fact part of the Symantec package by examining the path to executable images that back the processes. If they are part of the Symantec AV software package, you'll need to look in to configuring it to trust your application, or disable it while you run this code (not recommended), or simply ignore errors of this type.

How to refresh logon screensaver parameter changes?

I have a Windows service that may change the timeout on the logon screensaver in Windows (as described here.) To do that I change the following registry key to the timeout in seconds:
HKEY_USERS\.DEFAULT\Control Panel\Desktop\ScreenSaveTimeOut
The issue is that how do I make OS "read" or refresh the actual screensaver timeout after a change in the registry key above?
My practice shows that it is refreshed (for sure) only when I reboot the system, but in my case I need it to be applied without the reboot.
EDIT_1: After suggestion below I tried, as it seems to me, all possible combinations of the flags for the following:
DWORD bsmInfo1 = BSM_ALLDESKTOPS;
DWORD dwFlgs = BSF_FORCEIFHUNG | BSF_IGNORECURRENTTASK | BSF_NOTIMEOUTIFNOTHUNG | BSF_SENDNOTIFYMESSAGE;
int nbsm1 = ::BroadcastSystemMessage(dwFlgs, &bsmInfo1, WM_SETTINGCHANGE, 0, (LPARAM)L"Windows");
DWORD bsmInfo2 = BSM_ALLDESKTOPS;
int nbsm2 = ::BroadcastSystemMessage(dwFlgs, &bsmInfo2, WM_SETTINGCHANGE, 0, (LPARAM)L"WindowsThemeElement");
to no avail :( I receive 1 as a result from both calls but it has no effect.
I was able to resolve this.-.-.
If your service is running in the same session as the logon screensaver then you can call SystemParametersInfo with the SPI_SETSCREENSAVETIMEOUT flag.
SystemParametersInfo broadcasts the WM_SETTINGCHANGE message to all top level windows to indicate that a parameter has changed. If your code isn't running in the correct session then you could use BroadcastSystemMessage with the BSM_ALLDESKTOPS flag to deliver the WM_SETTINGCHANGE message. However, this does require the SE_TCB_NAME privilege, so your code would have to be running as SYSTEM.
I haven't actually tried this cross-session, so I can't guarantee that it works.

WinAPI: OpenProcess() returns error 5 with SeDebugPrivilege enabled for host process

I've got a routine where I process-walk to obtain the HANDLE of each process as I 'walk' down the list (which works fine), but my issue lies when I do:
HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID) where PROCESS_ALL_ACCESS is the access token, handle inheritance is set to FALSE, and pe32 is a PROCESSENTRY32
GetLastError() returns error code 5, and all the handles that are made are addresses which do not correspond to any appropriate process in Spy++32/64 (I've tried building the application under both platform targets, but as you'd expect, the result is the same).
The code for setting SeDebugPrivilege for the host process which I'm using is:
BOOL EnableDebugPrivilege(BOOL bEnable)
{
HANDLE hToken = nullptr;
LUID luid;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) return FALSE;
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) return FALSE;
TOKEN_PRIVILEGES tokenPriv;
tokenPriv.PrivilegeCount = 1;
tokenPriv.Privileges[0].Luid = luid;
tokenPriv.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
if (!AdjustTokenPrivileges(hToken, FALSE, &tokenPriv, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) return FALSE;
return TRUE;
}
Some questions that would be helpful to you:
I'm running Windows 7 x64 Professional.
Yes, devenv.exe is started with "Run as Administrator" privileges, which means that the debugger and the application itself are started under the same affinity.
I have tried toggling UAC or running the application with UAC off altogether. Still error code 5.
I just attempted doing it with PROCESS_QUERY_LIMITED_INFORMATION and I receive error code 6, or ERROR_INVALID_HANDLE. Also attempted with PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, result is error 5 again.
SeDebugPrivilege is enabled, verified with SysInternals' Process Explorer. Additionally, all processes that spawn from devenv/whatever the debugger is called inherit SeDebugPrivilege so...this is weird.
Thank you all very much for your time, I'm reaching wits end with this issue :S
Are you sure you are not passing 0 as a process ID value? The system idle process with ID 0 is included in the snapshot under the name [System Process], but you can't open a handle for it as the documentation for OpenProcess specifically says it'll fail. Well it says a bit more:
If the specified process is the System Process (0x00000000), the
function fails and the last error code is ERROR_INVALID_PARAMETER. If
the specified process is the Idle process or one of the CSRSS
processes, this function fails and the last error code is
ERROR_ACCESS_DENIED because their access restrictions prevent
user-level code from opening them.
Well, it's not completely true as I was able to open handle to CSRSS (of course, it doesn't actually have the requested rights). But it may fail for some protected processes (audiodg), so you shouldn't not do this. Instead, check the name of the process if it's the one you want.

HttpAddUrl fails with ERROR_SHARING_VIOLATION (32L)

I am attempting to write a price listener.
the data arrives as a 'push' response, ie: chunked transfer-encoding.
i have decided to use the http server api, as both async wininet and winHTTP read data apis both close the connection if there is no data for a short while.
first of all, am i correct to use the http server api?
second, if i try to, as per the msdn example:
retCode = HttpInitialize(
HttpApiVersion,
HTTP_INITIALIZE_SERVER,
NULL
); // return is NO_ERROR
retCode = HttpCreateHttpHandle(
&hReqQueue,
0
); // return is NO_ERROR
std::wstring url = _T( "http://apidintegra.tkfweb.com:80/" );
retCode = HttpAddUrl(
hReqQueue,
url.c_str(),
NULL
); // always fails with ERROR_SHARING_VIOLATION
i always get a sharing violation. do i need to use netsh to configure the connection somehow? if so how? ive seen mention of configuring http.sys, and ive even tried executing the above code as an administrator.
I would be extremely grateful for some help, as there seems very little code out there for this!
Many thanks,
Jon
This error happens if the port is already in use by another process. That means another application uses the port (for example IIS or another web server).