Race condition with WTS_SESSION_LOGON notification - windows

In my windows service I'm trying to perform some specific actions when an interactive user logs on to the system. For that I track WTS_SESSION_LOGON notification. Unfortunately today I discovered that that notification comes with a race condition.
For instance, if the user account is configured with a password, after system boot my service starts up and by the time the user enters their password, my service can receive WTS_SESSION_LOGON and process it just fine.
The issue happens when there's only one user account that does not have a password. Right after boot, the system automatically logs on that user but my service may start somewhat later and thus it does not receive any notifications of the interactive user logon.
Any idea if there's a way to address this issue? Or at least tell that the user session would auto-logon?
PS. The same race condition happens with WTS_CONSOLE_CONNECT notification.

When your service starts, it can use WTSEnumerateSessions() to find out which sessions are already present and what their current state is (connected, active/logged-in, etc) before then processing subsequent WTS_SESSION_CHANGE notifications in its HandlerEx callback.

Related

Sinatra / Warden / Ruby - How do I ensure that my users can only log in with a single session?

It's a requirement of the site I am building that users may only be logged in with a single session at a time. Should a user attempt to log in to the site from a different browser or machine while currently logged in, their login attempt needs to be rejected.
I've considered flagging the user object in the database as being logged in but this seems brittle to me as, if the user doesn't actually formally log out then the flag persists and the user gets unfairly rejected. To manage this I have to run some sort of cleanup task at regular intervals to ensure that those flags get reset, and this can introduce all sorts of other issues.
I'm using Sinatra as a core framework and Warden as an authentication manager. Is there a 'best practice' strategy for this sort of requirement?
this really is not an authentication issue, but a "how do I handle what happens when an authenticated user tries to login when they are already logged in" -- so you need to answer that question first. What do you want to do when someone is already logged in? Give the newest session priority? That is, kick the older session by the same user off?
Should a user attempt to log in to the site from a different browser or machine while currently logged in, their login attempt needs to be rejected.
and
if the user doesn't actually formally log out then the flag persists and the user gets unfairly rejected
are in direct conflict with each other. You have to choose which wins, the old or the new, and you've chosen the old… so there's nothing unfair there.
If you run a clean up then you're expiring their session, so you have to pick a time that works. This is an timeless problem for HTTP as it's a stateless protocol.
you could use a pseudo "forgot password" feature, where they can get an email sent to them that allows them to kick off the current user.
perhaps you could use websockets, which would allow you monitor the connection and kill the session if it dies at the other end. If it's still open though, you have the same choice as before.

How can I autostart a UI-application under windows that a non-admin user cannot close?

I have developed a C# Windows Forms application that runs in the background as a systray icon and does some stuff when it's clicked. It is supposed to launch when Windows starts and run continously, and a normal user without administrator rights shall not be allowed to shut it down.
What is the best way to do this? I initially intended to run it on the LocalSystem account through Task Scheduler, but then I learned (the hard way) about Session 0 isolation (i.e. the application will run but its UI elements do not show). When I run it with the logged in user, even if it runs elevated, the user can still shut it down through task manager (without requiring elevation).
Is there any way to give a process from LocalSystem access to the UI? I have a winlogon and a csrss process from LocalSystem running in session 1, so I guess it can be done, I just don't know how. Or is there maybe an easier way to disallow users to shut down a process of their own through the task manager? The only other option I can think of is to create an extra Windows Service that keeps polling if the app is running, and immediately launches it again if someone kills it - but that seems incredibly clumsy (also, I want it to stay dead when it crashed by itself, to avoid a single bug causing infinite loops of process creation).
Deponds on why they can't shut it down.
The natural way to go would to have created a service, started by a high priv account, and then had the desktop app just show what it was doing.
If there's something that they should see, but don't becasue they aren't running the service monitor app. (and acknowledge message back to the service), send them an email, send their boss an email, send yourself one and then go shout at them.....
Be a lot easier than trying to get the lid back on this tin of worms.
A nice way to make sure the desktop app is ruuning, would be simply to schedule it to run every X, but drop out immediately if it already is or the somethingwenthorriblywrong flkag is set.
Not worth writing a service to check if it's still there, as they could kill that as well, unless you want to make that a service they can't kill. :(
You are trying to be too draconian with this. Add some sort of auditing so you can see it dies or was shutdown, monitor that and deal with any adverse reports. It's a heck of a lot easier, and gives manage something to do...
You can run an administrative process in the user's logon session. One method would be to for a master process (a system service) to duplicate its own token, use SetTokenInformation to change the session associated with the token, and then call CreateProcessAsUser. The lpStartupInfo parameter can be used to associate the process with a particular window station and desktop. It may be necessary to explicitly change the permissions on the window station and desktop first.
HOWEVER, this is a bad idea from a security standpoint, because GUI applications are vulnerable to malicious messages sent from other processes on the same desktop ("shatter attacks").
It would be safer to run the process in the user's own context but apply an ACL to it. This can be done using the lpProcessAttributes parameter to CreateProcess or CreateProcessAsUser, or with the SetSecurityInfo function. I've never tried this, but it should in theory prevent the user from using task manager to close the process.
If you are creating the process from the user's context, then the user will be the owner, so a sufficiently knowledgeable person could change the permissions back in order to terminate the process. If you need to block this hole, using CreateProcessAsUser from a privileged master process (the token can be duplicated from one of the existing processes in the user's session) should (again, in theory) mean that the user is not the process owner.
Another potential issue: if you listen for messages indicating that the user is logging out (in order to exit) such a message could be faked. If you don't then you need to find some other way of exiting when the user logs out. You may need to experiment here, I'm not sure how the system will react.

Launch a winform application from a windows service

Please let me know how do I run the app under current logged in user from the service.
To give you background, I have a VB.NET Windows service whose sole functionality is to run a Winform App at a specified time. Apart from that it also sets a system wakeup timer so that the system can be woken up at the specified time, if it goes into standby/sleep, to run the app. This service has to cater to XP/Vista/Win7 desktops on our network. This service won't run on servers and laptops.
The Winform App shows a UI for the user to provide some inputs. If the user does not provide the input within 15 minutes, then it defaults the value and then goes into system tray icon. The user can click on the icon and change the values later (within in a specified time frame and that too only twice).
There is absolutely no interaction between the service and the winform app apart from the service starting the app. It also monitors if the app has been killed by the user/crashed. If it has been killed/crashed, then a new instance is run after 30 mins from previous run.
If there is no user logged on, then also I want the app to be run at the specified time. As I said before, the app has a default timer. So if some user has just logged off from the system, then defaults would be set by the winform app.
Now coming to why I am stuck with this design - I cannot use TaskScheduler because it has been disabled on all machines and security team is not willing to change it. TaskScheduler had the option to wakeup the machine from sleep and other things. So basically I ended up creating a service which is acting like task scheduler.
Currently when I run the app.exe via process.start() within the service, its running under SYSTEM account as the service is also running under LOCAL SYSTEM. So basically I am not getting any UI. Is there anyway to run it under the current logged in user? I am not worried about multiple user login as we wont be running it on servers and switch user is not enabled on our desktops. Even if somebody has done a remote login via mstsc, then also I need the run the app and show the UI to the user.
Please let me know how do I run the app under current logged in user from the service.
Thanks
askids
There were some additional comments that I posted. But I somehow cannot see it :(
Coming back to the original question. I was able to figure it out after several trial and errors. I will put it in detail.
With Vista and above, services run in isolation from other user sessions. They run in session 0. User sessions run in 1 and above. So basically you need to emulate the process as current logged in user.
Use WTSEnumerateSessions and
get of sessions. Check if the sesion
state is active. This will be
current logged on user session. If
there are no active sessions, it
means there is no logged on user. In
my case, there will be only 1 logged
on user. So I need not figure out
the active session (like others may
need to do).
Use WTSQueryUserToken to get the user token in the active session.
Create a primary user token using DuplicateTokenEx
Create an environment using CreateEnvironmentBlock
Use the information above in the CreateProcessAsUser
The reason why it was working in XP and not in Vista was because it looks like the startup default information is different. After I set wShowWindow flag of the startupinfo structure, the GUI would start appearing.
Dim StartupInfo As New STARTUPINFO()
StartupInfo.cb = Marshal.SizeOf(StartupInfo)
StartupInfo.dwFlags = STARTF_USESHOWWINDOW
StartupInfo.wShowWindow = WINDOW_STATUS.SW_SHOWNORMAL
One more additional info. I was trying to set the default desktop using
StartupInfo.lpDesktop = "WinSta0\\Default"
because of which the application would crash upon launch. So I commented it out.
I still have one final issue. The launched app is not in focus. The GUI appears, but in background. But I am thinking, it will once again have to do with some parameters like above. Once I figure it out, I will add in the details.

How does fast user switching affect a windows service?

How does fast user switching affect a windows service? Are the services suspended or do they keep running in the background when a different user logs in?
On Vista, services run in session 0. This session is always running. User sessions are session 1 on up. Even as users connect and disconnect from sessions, log on to new sessions, and so on, the services keep running and session 0 is never torn down. The only effect on services is they (optionally) receive notifications such as session connect, log on, and so on.
On XP, services run in session 0 and so does the initial user who logs on. This session is never torn down, and may or may not have an interactive user connected to it. Besides this, the behavior is the same as Vista.
They keep running; they run as their own users (whatever you set).
Windows services run in the background even if no user is logged in. Switching between users should have no impact on a properly written service.

How can i be notified that the user is logging out?

I am writing a user agent that needs to perform some cleanup when the user logs out of OS X. The agent is NOT receiving a SIGINT (neither SIGTERM, and neither SIGKILL) signal. Because of this, the agent process is remaining as a "ghost" process running on the Mac, and it will no longer respond to any attempts I do to kill it. I need to be notified that the user is logging out and then I can handle the shut-down of the Agent gracefully.
I know about the CFNotificationCenter, but I could not find any example on how to use it for logout. Actually I did not find a list describing the possible notifications (at least the standard ones) that I can observe using the CFNotificationCenter. Can anyone help me please ?
Regards
Alan
Apple has a document describing how this is done. Essentially, you use the SCDynamicStoreCopyConsoleUser to check the currently signed in user. If this is loginwindow, you know that no user is logged in. You can then register for a notification whenever the current GUI console user changes.

Resources