I'm trying to figure out how to detect when the user presses the power key on the keyboard.
I'm developing a kiosk application and I want to run a routine when the user want to force shut down the computer by pressing and holding the power key.
Thank you in advance.
There are no methods that will be called when a user presses and holds the power key. That's directly handled in hardware and doesn't even get routed to the OS, much less to your application - it's the equivalent of pulling the power cord.
Your best bet is to create a "clean shut down" user preference key or temporary file that your app will remove as part of its normal shutdown procedure. When your app starts up, it can then check for it to see if the previous run was shut down normally, or had the rug yanked out from under it.
Oh, and since this is a kiosk - don't give users physical access to the power switch to begin with. Sometimes the simplest solutions are best!
You don't.
From Apple's Cocoa Event Handling Guide:
Note: Lower levels of the system trap
and handle some events early in the
event stream. These events are never
routed to a Cocoa application. These
events are generated by reserved keys
or key combinations, such as the power
and media-eject keys.
You can make your application perform some action and/or prevent a shutdown with applicationShouldTerminate, somewhat covered at the Graceful Application Termination doc page. This won't be exactly the same as just responding to the key event, though.
You can also use the NSApplicationPresentationDisableSessionTermination flag to just disable logout and shutdown.
Related
First off, I know some proper ways of making a truly interactive Windows Service.
The situation is, I do have a tool that does not interact with the user as such. However, it does display non-blocking notifications both via popup windows and via the Windows Notification Area (aka System Tray). It also writes a logfile of the notifications it displays.
This tool is normally spawned by a main user application and as long as the main application is a normal application, these notifications do work as intended.
When this tool is spawned by a Windows Service, no notifications are displayed, naturally. (The Desktop Session for the service isn't visible.) But this would be OK, we have the logfile and these notifications are just - notifications, nothing the user absolutely must see under all circumstances.
The question now becomes: Is a process running in the context of a Service (the Service itself or any process it starts) "allowed" to make Windows API calls that display a visible GUI?
Will most Windows API calls (e.g. creating and showing a window, using Shell_NotifyIcon, etc.) behave the same in the invisible session of the service?
Or would I have to make sure throughout the source code, that no GUI displaying/modifying stuff is called in the context of the service?
And yes, calling ::MessageBox is a bad idea because it will block. But I can handle these calls.
And yes, this could be designed better, but it's what I have at the moment and it would be nice if I hadn't to rip the whole tool apart to make sure no GUI related code is run in the service.
GUI elements from a Windows Service are shown on Session 0. On Windows XP & 2003, users were allowed to log in to Session 0 and interact normally with the windows created by a service, but Microsoft put a knife in the heart of interactive services in Vista (and beyond) by isolating Session 0.
So, to answer your specific questions:
Is a process running in the context of a Service (the Service itself
or any process it starts) "allowed" to make Windows API calls that
display a visible GUI?
Will most Windows API calls (e.g. creating and showing a window, using Shell_NotifyIcon, etc.) behave the same in the invisible session
of the service?
Yes, GUI calls are allowed and should succeed as normal. The only notable exceptions that I know of are those related to tray icons because the process providing the task bar (explorer.exe) is not running in the isolated Session 0.
Or would I have to make sure throughout the source code, that no GUI displaying/modifying stuff is called in the context of the service?
That should not be necessary, though you should proceed cautiously with any GUI interaction from your service. Test thoroughly!
I would like to provide some info wrt. Raymonds Chen's comment to the other answer
You should avoid presenting UI in a service because you may trigger
the UI Detection Service which will switch the user to your service UI
temporarily. – Raymond Chen
I find these good articles:
What is Interactive Services Detection and Why is it Blinking at Me?
Inside Session 0 Isolation and the UI Detection Service, Part1, Part2
Where one can find explanation on what the UI detection service (UI0Detect) is and does and how it's supposed to work.
Interactive Services Detection (the blinking button on the taskbar) is
a mitigation for legacy applications that detects if a service is
trying to interact with the desktop. This is handled by the
Interactive Services Detection (UI0Detect) service.
However, one must note that this only can work if the service that is trying to view a GUI has the flag "Allow service to interact with desktop" set, because only then the service process will be running on WinSta0of Session0 even allowing it to show anything at all.
Alex Ionescu mentions this:
If UI0Detect.exe ...
the SCM has started it at the request of the Window Hook DLL. The
service will proceed ...
The service first does some
validation to make sure it’s running on the correct WinSta0\Default
windowstation and desktop and then notifies the SCM of success or
failure.
So, to come back to Raymond's comment: As far as I can see, as long as a service doesn't tick the type= interact option (see sc.exe), and normally you don't tick this, the UI0Detect service doesn't do anything and there shouldn't be any "danger" of triggering it.
Note: The information above is based on my limited research and tests on only a single Windows 7 PC.
Say I have a Windows GUI applications with a buttons on it. I am able to simulate a click on that button by using sendMessage winapi calls with BM_CLICK as the parameter to the call.
Now, from a security perspective, I do not want this to happen. i.e. my target process should ignore sendMessage calls from another process. Is there a provision to do this at all ? A way to authenticate the sendMessage calls ?
EDIT: In other words, how can I prevent applications such as Enabler, TurnitOn http://www.raymond.cc/blog/how-to-enable-and-access-disabled-grayed-out-buttons-windows-and-checkboxes/ from accessing functionality that is not meant to be accessed by the user ?
If the application is running in the user's own context, then it can only do what the user can do. The corollary of this, often overlooked, is that anything that the application can do, the user can do.
So there's not really any point in worrying too much about whether a button on such an application is "really" disabled or not. The user can always find another way to do whatever the button was going to do anyway. (This might be by using a registry editor, obtaining another application with the same functionality, or, if nothing else is convenient, they can run the application inside a debugger and force it to re-enable the button.)
The appropriate solution depends on the context:
In many cases, the most appropriate solution is to stop worrying about it. You should be able to trust your users, and if you can't, that's an HR problem, not a technical problem.
If the application is providing an interface to something running in a higher context, such as, for example, the front end for anti-virus software, then the security decisions (is the user allowed to do this?) should be happening at the back end. That is, the security decisions need to be taken by code that isn't in the user's control.
If you're a system administrator trying to lock down a kiosk machine - a machine that is going to be used by untrusted users, typically using a single guest account of some sort - then you use AppLocker or Software Restriction Policy to define which applications the user is allowed to run. Since Enabler and TurnItOn won't be on your list, the user won't be able to run them to bypass your security policy.
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.
The sole user interaction for my app is through the accelerometer, so there is never a reason for the user to touch the screen. What I need is the ability to elevate a non-touch event so that the system recognizes it as user interaction, delaying the screen timeout. Either that or I need to be able to manually extend the timer.
I have already read (and commented on) the thread about disabling the timeout. That is not what I need. The interaction my users are performing is very explicit (turning it over 180 degrees) so it won't happen if it is set down or stuck in their pocket (unless they are riding a rollercoaster.
Currently, the device is constantly shutting down when the user is in the middle of actively using my app.
Have you tried flipping UserIdleDetectionMode from enabled to disabled again to see if it resets the timer? If that works you could do it in response to your application events.
Otherwise there is no means of simulating user events, so I would say you are out of luck on this one for the moment.
I maintain a variety of managed userlabs on a university campus. These machines all currently run Windows XP and we have a windows service that is used to "lock" a machine by blocking any keyboard or mouse input. The locking happens during our scripted OS installation so that users aren't able to accidentally halt or break the process. It is also used to prevent users from logging into machines until they are checked out at the front desk of a given lab. Ctrl+Alt+Del is blocked via a keyboard filter driver and the rest of the keys and mouse are currently blocked using the BlockInput() function from user32.dll.
In XP, the service runs as Local System and the checkbox for "Allow service to interact with desktop" must be enabled from the BlockInput() call to succeed. Under Vista, this no longer works I'm guessing because of the Session 0 isolation changes. The call succeeds, but input is not actually blocked.
The keyboard filter driver still works just fine and we can use that to block the whole keyboard instead of just Ctrl+Alt+Del. But I'm at a loss as to how we're going to block the mouse now. I'm not even entirely sure the Session 0 isolation is to blame.
Can anyone recommend a fix or a workaround to allow us to block mouse input from a service in Vista and beyond? I've looked for alternative win32 API's without luck. Assuming Session 0 isolation is to blame, is there a legitimate way to call the function from Session 1 or would that sort of defeat the purpose of the isolation? Will I have to rely on an elevated companion exe that runs on user login and communicates with the service?
From a service, you can use WTSEnumerateSessions to get all logged on user sessions, WTSQueryUserToken to get the logged on user's token, and then use CreateProcessAsUser with that token to get code running on the user's desktop. This has the disadvantage that the code will run as the logged on user. Since all input is disabled, this is probably safe enough and is at least as safe as the existing XP solution.]
EDIT: BlockInput requires a high mandatory integrity level. You could try adding this group to the token, but then you have code with higher privileges running on the desktop and potentially open to attacks.
An alternative might be to use your service just to disable all HID class devices on the machine.