Trying to interpret user session states on Windows OS - c++

If I call the following API from a local service running on Windows 7:
WTS_SESSION_INFO* pWSI;
DWORD nCntWSI;
WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, NULL, 1, &pWSI, &nCntWSI);
and then go through all returned WTS_SESSION_INFO structs in pWSI and check WTS_CONNECTSTATE_CLASS State members, can someone explain what is the difference between WTSActive and WTSConnected?

Connected means the user has connected and has been (or soon will be) presented with a login screen but hasn't completed it and been verified yet. He might be typing his password, for example.
If the user has locked the workstation, it's been locked by a screensaver, or he has switched to another user account, it doesn't end his session. The user remains logged in and his session would remain marked active. So being connected but not active means there are no processes running under that user's account. (The one caveat being there could be a service or other process running in a separate session under that user's credentials, but that's a different matter.)

Related

CreateProcessAsUser creates blank/black window

I'm using CreateProcessAsUser to create a process under user-specified credentials.
I'm posting what are hopefully the relevant parts of the code. Let me know if you want to see anything more.
First LogonUser to get the token:
result = LogonUser(
username,
wcschr(username, '#') ? NULL : (domain ? domain : L"."),
password,
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
&hrunastoken);
I then load the profile, set the lpDesktop value of the STARTUPINFO structure to NULL (which makes it use the desktop of the calling process), and call CreateProcessAsUser:
result = CreateProcessAsUser(
hrunastoken,
NULL,
apptorun,
NULL,
NULL,
FALSE,
CREATE_UNICODE_ENVIRONMENT,
envblock ? envblock : NULL,
NULL,
&si,
&pi);
This works fine - it logs in and creates the process successfully, and the process "works". The problem is that the windows it creates are black, as in this screenshot of a notepad process started with my program:
Possibly relevant context:
My account is a local account on a Windows 7 machine with full admin rights, and I am logged on with that account. I used psexec (Sysinternals utility) to open a command prompt running interactively under the local system account. I am launching my program from that command prompt. The credentials I am passing to it are from my account.
I have not done anything with permissions to windowstations/desktops; I assume the process I create should have rights to those as the process is being created in my session and using the same account I'm already logged in with - albeit going through the SYSTEM account first. Using Process Explorer, I don't see any difference in the permissions on the values and handles to windowstation/desktop by the process opened via my program vs opened normally. Maybe that's completely irrelevant.
I also cannot use CreateProcessWithLogonW function because it must work when run from the SYSTEM account - that function as well as the "runas" program that comes with Windows don't work under SYSTEM.
Funnily enough, I can't use my current method to open processes unless I'm running it under the SYSTEM account, as "a required privilege is not held by the client", so I can't compare the windows created when starting my program under my account vs the SYSTEM account...
The default DACL for window stations and desktops grant full access to the logon SID (which is unique to the current logon session) rather than to the user's SID. (The user's SID also appears in the DACL for the window station but has only limited permissions. It does not appear in the desktop DACL.)
The call to LogonUser generates a new session (and associated logon SID) rather than reusing the existing one, so your process does not have access to the desktop, and only has minimal access to the window station. (Actually I'm slightly puzzled as to how the process manages to run at all; when I tried to reproduce your results the process exited immediately with exit code 0xC0000142, as expected.)
The second piece of code in this answer shows how to change the DACL on the window station and desktop to allow the process to run properly. (This may not be the best solution, however, depending on your specific goals.)

How to logoff a user when the workstation is locked?

I wrote a Windows application that comes with two modules: service and user-mode applications. The service implements its own scheduler and may log-off a user at a predefined time. For that I was using the following call that is triggered from my user-mode module running in a logged-on user session that has to be logged off:
BOOL result = ExitWindowsEx(EWX_LOGOFF, reason);
This works fine, except of the situation when a user's account is locked. In that case that API doesn't seem to do anything at all even through I get 1 returned from it.
So I was curious, is there any other way to log off a user when their account is locked? (One condition I have in this case is that if that user had any unsaved documents then the log-off should not be forced.)
Try this:
DWORD dFlags = EWX_LOGOFF | EWX_FORCE | 0x10200;
BOOL result = ExitWindowsEx(dFlags, reason);

Are session IDs obtained by WTSEnumerateSessions API unique?

Say, if at one point in time I call WTSEnumerateSessions from a local service application and obtain the list of current user session IDs. So if at some later time I need to know if some particular user session is still in the same state, can I rely on WTS_SESSION_INFO::SessionId to be unique? And if not, how to do this?
Windows gives a SID to every logon session. MSDN has sample code to look it up and it is garanteed to be unique and constant for a given logon session. If the user logs out and logs back in again, he will be attributed a new Logon SID.
If the same user is logged locally and logged on remotely at the same, there will be a different Logon SID for each logon session. This image shows what I mean :
.
(Disclaimer - I stole it from a blog post of mine)
You can get the Logon SID with this command. It can be usefull to play what-if scenarios without writing any code.
c:\>whoami /logonid
S-1-5-5-0-329693570
Tested on Windows Server 2008. YMMV on other versions.
Session id is assigned as the lowest unused number at the time of login.
So if I had ID 1, then logged off, and you log on you would get ID 1 too as 1 was available when you logged on.
If I never logged off you would get ID 2 due to ID 1 was in use. If I then logoff and you stay on the next user will be assigned ID 1 again (not 3) because 1 was the lowest unused number.
A session ID is not the same as a security ID. A session might have someone logged into it in some state, or might not have someone logged into it. You could call WTSEnumerateSessions and find that someone is logged in at session 1, later that person could log out, later someone else could log in and Windows might give them session 1, and then you call WTSEnumerateSessions again. So the state might be the same as it was before, after undergoing two changes and being used by a different user than before. Do you call this unique? I don't know what you mean by unique.

How to get the logged on user from a process running as root?

I have a program running as root and call another program to run(A).
I want A to run when the user logs on. I've used command: su - 'username' -c A,
or in the A main function, I've called: setuid(current_uid_logged).
But I don't know the way to get the user-name of the logged on user, or the uid in the root process.
Ways that I've tried: getenv("USERNAME") or getlogin() always return root account.
I've confused with getlogin(), my program is running when kernel start and wait for user login (I have a thread to wait a Finder process (Mac OSX) running to detect user logged on), wait 10 seconds and call getlogin() but sometime, it returned root but can return user login. I think Finder process is running when user logged on.
But when I call my app to run with sudo command, getlogin() always returns current user logged on.
How do I do this?
getlogin(3) returns the name of the user who owns the process's controlling terminal. This has nothing to do with the username of whoever might log in to the GUI of the operating system. Instead, getlogin(3) and getuid(2) will only ever return the name / uid of the user account that started the program -- they have more to do with the process history than with any user sitting in front of the computer.
There are similar stories with the environment variables USER and LOGNAME -- if either one was set in a process, it was by a process higher in the process's call tree. It too cannot be influenced by whichever user eventually sits in front of the computer.
I'm sure there is some mechanism to discover the currently-logged-on user on an OS X machine, but it won't be a traditional Unix API that provides it to you.
how about uid_t getuid()?
more details at http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man2/getuid.2.html

How to know whether I have admin authority in windows?

Is there any APIs in windows to detect whether the current user(current now) has the admin authority?
BOOL IsHasAuthority()
{
}
Many Thanks!
How to Determine Whether a Process or Thread Is Running As an Administrator
Use this solution when you are writing
an application that must determine
whether any of the following is true:
The current user can perform administrative tasks. The current
user is a member of the
Administrators group. A supplied token handle represents an
administrator with an elevated token.
A token handle represents a user who is a member of the
Administrators group.
The program is running with an elevated token or needs to spawn a
child program that is elevated so it
can perform administrative tasks.
You can use the Windows API function CheckTokenMembership(). The MSDN documentation for that function has an example demonstrating how to check for membership in the Administrators local group.