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

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.

Related

Windows: Detect in Registry when a user is logged in but disconnected

When I log in into an windows device, I can sometimes see 2 users sessions (I can see it by clicking Task Manager -> Users). One of the users has status Disconnected and the other active
Is there a way for me to see weather the user is disconnected or not in the registry?
Thank you
I don't know if there is a registry value you can check and if you find one it must be considered an unintended side effect you should not rely on.
The WTS API is the correct way to handle this.
Call WTSRegisterSessionNotification to receive notifications and/or WTSEnumerateSessionsW to find the current sessions and their states.

How to keep a user process running until Windows logoff is definite?

I have an application that is running on Windows, in the user's session, that I don't want the user to be able to close by accident.
One way the user can close it is by having unsaved data (e.g. in notepad) and start the process of logging off. Notepad rejects the WM_QUERYSESSION message; Windows prompts the user that there is unsaved data; and the user gets to cancel the logoff.
Other applications (including mine), get the WM_QUERYSESSION, respond with TRUE, then get WM_ENDSESSION, and quit. Importantly, they quit before Windows has even decided to prompt the user about unsaved data in notepad.
If the user cancels the logoff, the end result is that the user's session continues without all the processes that honoured the end session messages.
What I'm trying to find a way of doing is keeping my process running until we're past the point that the user could cancel the logoff. Looking at the microsoft docs on this, I don't see an obvious way of doing that - each process goes through its own WM_QUERYSESSION > WM_ENDSESSION, and the docs are explicit that this happens for each application independently.
I don't want to reply to WM_QUERYSESSION with FALSE, as I don't want to block the logoff myself, just stay running if something else blocks it.
Are there any other ways of finding out when Windows has decided that all the WM_QUERYSESSION messages were replied to with TRUE, and the logoff is inevitable?
(I think this is a Windows question, rather than a question specific to the language I'm using, but in case it matters, it's PureBasic. Any Win32 API approach should be workable though.)
If any app returns FALSE to WM_QUERYENDSESSION, apps that had already returned TRUE will receive WM_ENDSESSION with wParam=FALSE to indicate shutdown has been canceled.
If all apps return TRUE to WM_QUERYENDSESSION, only then will they receive WM_ENDSESSION with wParam=TRUE to indicate shutdown is proceeding.
See Application Shutdown Changes in Windows Vista and Restart Manager: Guidelines for Applications for more details of how WM_QUERYENDSESSION and WM_ENDSESSION work.
Is your app paying attention to the wParam value given by WM_ENDSESSION? Or does it just blindly exit unconditionally when it receives WM_ENDSESSION? Not all apps pay attention like they should be. Make sure yours does.
Update: Per the WM_QUERYENDSESSION documentation, and the Logging Off documentation:
When an application returns TRUE for WM_QUERYENDSESSION, it receives the WM_ENDSESSION message and it is terminated, regardless of how the other applications respond to the WM_QUERYENDSESSION message.
So, there is really nothing your app can do here. Once it responds TRUE to WM_QUERYENDSESSION, that is it, game over. Your app will receive WM_ENDSESSION and be forcibly terminated if it does not exit within a few seconds, regardless of how other apps respond to the shutdown.
So, the only way I can think of to really detect when the session is actually ending is to use a service instead, as a service can receive SERVICE_CONTROL_SHUTDOWN and SERVICE_CONTROL_SESSIONCHANGE notifications.

Race condition with WTS_SESSION_LOGON notification

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.

Is it possible to find out whether a process was started by a user or by another process via CreateProcess or ShellExecute?

I wanted to know if there was any way of checking if a particular process was started by the user by him/her double clicking, typing the required commands in cmd, via the address bar in explorer, etc. or by another program using CreateProcess() or ShellExecute().
I tried checking the parent process id of the created process but failed to see any consistency among the parent pids of the user initiated processes. I wanted to know if there was any other way or a fool proof way using the ppids.
First you have to determine what the "process started by user" means to you. From Windows' point of view all the processes are started by another processes, whether it was somehow triggered by user or not.
I can only think of getting processes belonging to currently logged on user otherwise i doubt that you can distinguish processes created on a system.

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.

Resources