Open greatquux opened 4 years ago
BTW this is ntop 0.3.4, the latest release binary. I haven't compiled the latest code, but I don't think any of the recent commits seem to relate to this.
It seems that either GetTokenInformation
or OpenProcessToken
fails probably due to missing permissions. Could you try running as administrator? For now it only says "SYSTEM" because that's just the default user name I set.
I am running it as a local machine (and domain) Administrator, and UAC is completely disabled (EnableLUA set to 0). That's why in my screenshot I included Task Manager also to show I can see the usernames in there.
Unfortunately I have no TS setup and there seems to be no error code shown nor any kind of logging/tracing going on. Process.UserName
is set to SYSTEM
(_tcsncpy_s(Process.UserName, UNLEN, _T("SYSTEM"), UNLEN);
) by default before attempting to open the process (OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, Entry.th32ProcessID);
).
And my knowledge of Active Directory is rather limited. The doc for LookupAccountSid declares that the first parameter (lpSystemName
), if NULL, looks on the local system first, then on trusted domain controllers (relative to the local computer), and if the machine is on an untrusted domain, that the parameter should be set.
But then I have not much of an idea for a trusted computer (joined?) on a domain. I feel like NULL
is the same as "."
and the name of the computer, but that could be tested out with a snapshot build could be done to show the error code (e.g. e00000000
) to get a better clue.
List of possible failures:
OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION...
returned NULL
UsedMemory
is unset, either this or GetProcessMemoryInfo
failedOpenProcessToken
returned FALSE
GetTokenInformation
didn't set its error code to ERROR_INSUFFICIENT_BUFFER
GetTokenInformation
returned FALSE
LookupAccountSid
failedOne thing I noticed is that the handle is never closed after the OpenProcess
call. Microsoft recommends closing it when done.
My best guess is probably that the processes are protected as noted in https://docs.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights#protected-processes due to the handle being NULL (Io counters are unset as well).
Next question would be, is it a local Administrator account or one from the domain, if it's joined a domain?
The server is joined to a domain, and it's a domain Administrator account (that is a domain admin and local machine admin) that I'm logging into. Task Manager (and also Process Explorer) must be doing something different to get the user names as they show up there. I'll see if I am able to do a build myself and show any error codes.
It looks like LookupAccountSid is getting error 122, ERROR_INSUFFICIENT_BUFFER. That's the only error code I ever see, I just put a little GetLastError !=0 check after LookupAccountSid and printed it, but I'm not advanced enough in Win32 C programming to get much farther. :( I found a forum thread https://social.msdn.microsoft.com/Forums/en-US/b0c6d946-92a7-4f52-8809-4b8f72010219/lookupaccountsid-fails-with-strange-errors-in-a-thread-that-is-impersonating-a-pipe-client?forum=windowssecurity that seems to indicate you can just reallocate the buffer to make it a bit larger and try again?
ERROR_INSUFFICIENT_BUFFER
directly from LookupAccountSid
? That's surprising, since the account username is typically smaller than 256 (UNLEN
) characters and the domain name is typically smaller than 260 (MAX_PATH
) characters.
My main guess remains that OpenProcess
returns NULL because it either has no permission or is simply incapable of processing the query for TS user processes since no other process information is filled out in your screenshot (e.g. used memory, which is processed before username, but only if it has a handle from OpenProcess
).
It's possible that Task Manager (and other clones alike) use GetSecurityInfo
(https://social.msdn.microsoft.com/Forums/en-US/b0c6d946-92a7-4f52-8809-4b8f72010219/lookupaccountsid-fails-with-strange-errors-in-a-thread-that-is-impersonating-a-pipe-client?forum=windowssecurity)... But then I'm not seeing the function being imported in taskmgr.exe
.
Unfortunately my knowledge of Win32 is pretty limited too. I know no foss task managers
This is how ReactOS' taskmgr does it btw: https://doxygen.reactos.org/d7/dd5/perfdata_8c_source.html
Weirdly, I'm getting error 122 from LookupAccountSid even on my Windows 10 computer which works and displays the user names and memory correctly, and also on the remote desktop server which doesn't. But in each case, I do see a non-NULL value for Process.Handle. And all this is taking place right after the call to LookupAccountSid that is if(OpenProcessToken()) block, which is inside if(Process.Handle) so it should have a value.
My print statements in that screenshot come right after the call to LookupAccountSid and before the FIXME comment:
Where do you think I should put a ConPrintf to check on a variable?
EDIT: GitHub doesn't like when I send screenshots via email (Evolution).
Interesting. Although seeing your snippet: I just remembered that the error code is only set when an error occurs, otherwise I think a successful call doesn't set the errorlevel for the thread (from the first GetTokenInformation
). So it's normal you also see 122 on Windows with the provided snippet.
A better thing to print would be the result of LookupAccountSID
(if it returns 0 then it failed).
@gsass1 That's interesting. Would you have a quick idea why the other fields (e.g. UsedMem, CPU time) are unset? I could try checking but I doubt I'd have anymore clue.
I saved the result from LookupAccountSID in a BOOL and it always came out 1, I put an if() around it and will only print it if's not true but I haven't gotten anything out of it. Interestingly, I tried it on another RD server that is not on a domain, just workgroup with local accounts, and even there we see that it can't get CPU, memory, or username values properly. Task Manager is included to show that it has them:
Looking at the ReactOS code: Curious that ReactOS does OpenProcessToken(hProcess, TOKEN_QUERY, &hProcessToken)
betwen instead of TOKEN_READ
as used in ntop. Want to try with TOKEN_QUERY
instead? (Note: TOKEN_READ = TOKEN_QUERY | TOKEN_READ)
Otherwise curious if TokenUserStruct->User.Sid
is set to NULL by the later GetTokenInformation
.
Ugh. Still a mystery. Changing to TOKEN_QUERY had no effect. User.Sid is not NULL (and it seems to have valid values when I print it out). If I change the default SYSTEM to something like "default" in most cases it does come back as "default" so it's definitely not writing anything in there.
Checked around a bit (Well-known SIDs) and there values that have special meaning (e.g. S-1-1-0
for 'null' and S-1-5-32-555
for DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS
(thanks Microsoft)). Since it's non-null, do you mind printing/checking a few SID values as examples? From there I'll have a better clue.
The ReactOS code is nice but it does not even support logging via Active Directory (see LDAP/ActiveDirectory
at Missing ReactOS Functionality) so I doubt their Task Manager would be able to translate anything. Curses.
Sorry if I'm taking too long. Tonight I'll try getting 2008 R2 up and running and try something out.
I think I have finally figured things out. Once I got SIDs to print properly, and found I needed to use printf to properly redirect output to a file, and remembered my C pointer lessons from 25 years ago, I finally saw that the process loop was skipping over anything it couldn't get the info for on my RD server. The OpenProcess() call right after setting the default ExeName and UserName was failing but not because the Handle was NULL, because it did not have sufficient rights. On my workstation this happens to csrss.exe and the Idle process only, but on the RD server it was for everyone else.
If I run ntop.exe as SYSTEM, I can see all the usernames properly (and presumably the other stats). It looks like you need to give ntop.exe the SeDebugPrivilege privilege (or at least do it with a command line option) so that it can read stats on everything. It took a while to figure it all out, but as always, it was good to learn!
That's particular. Maybe I should add a command-line option for SeDebugPrivilege
? (Or maybe PROCESS_ALL_ACCESS
)
Maybe, but definitely experiment first on your computer to see if you are able to access the information about the csrss.exe process first. Right now I am having trouble even giving myself the SE_DEBUG_NAME privilege (even though I'm a local machine admin with UAC turned off) and I should really get back to "real work". :)
For some reason, all usernames (except Administrator where I'm running ntop) show up as SYSTEM when I try to run it on a remote desktop server. The processes are there, just USER is showing as SYSTEM. Any idea why or how to fix?