I have written a Windows service that allows me to remotely run and stop applications. These applications are run using CreateProcess, and this works for me because most of them only perform backend processing. Recently, I need to run applications that present GUI to the current log in user. How do I code in C++ to allow my service to locate the currently active desktop and run the GUI on it?
Roger Lipscombe's answer, to use WTSEnumerateSessions to find the right desktop, then CreateProcessAsUser to start the application on that desktop (you pass it the handle of the desktop as part of the STARTUPINFO structure) is correct.
However, I would strongly recommend against doing this. In some environments, such as Terminal Server hosts with many active users, determining which desktop is the 'active' one isn't easy, and may not even be possible.
But most importantly, if an application will suddenly appear on a user's desktop, this may very well occur at a bad time (either because the user simply isn't expecting it, or because you're trying to launch the app when the session isn't quite initialized yet, in the process of shutting down, or whatever).
A more conventional approach would be to put a shortcut to a small client app for your service in the global startup group. This app will then launch along with every user session, and can be used start other apps (if so desired) without any juggling of user credentials, sessions and/or desktops.
Also, this shortcut can be moved/disabled by administrators as desired, which will make deployment of your application much easier, since it doesn't deviate from the standards used by other Windows apps...
The short answer is "You don't", as opening a GUI program running under another user context is a security vulnerability commonly known as a Shatter Attack.
Take a look at this MSDN article: Interactive Services. It gives some options for a service to interact with a user.
In short you have these options:
Display a dialog box in the user's session using the WTSSendMessage function.
Create a separate hidden GUI application and use the CreateProcessAsUser function to run the application within the context of the interactive user. Design the GUI application to communicate with the service through some method of interprocess communication (IPC), for example, named pipes. The service communicates with the GUI application to tell it when to display the GUI. The application communicates the results of the user interaction back to the service so that the service can take the appropriate action. Note that IPC can expose your service interfaces over the network unless you use an appropriate access control list (ACL).
If this service runs on a multiuser system, add the application to the following key so that it is run in each session: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run. If the application uses named pipes for IPC, the server can distinguish between multiple user processes by giving each pipe a unique name based on the session ID.
WTSEnumerateSessions and CreateProcessAsUser.
Several people suggested WTSEnumerateSessions and CreateProcessAsUser. I wonder why no one suggested WTSGetActiveConsoleSessionId, since you said you only want to target one logged in user.
Several people sure are right to suggest CreateProcessAsUser though. If you call plain old CreateProcess the way you said, then the application's GUI will run with your service's privileges instead of the user's privileges.
That problems Session 0 , Interactive Services ,
Windows Service Allow Service To Interact With Desktop
on Windows 7 or Windows Vista
You can read this article
http://www.codeproject.com/KB/vista-security/SubvertingVistaUAC.aspx
I try explained here it's working on Windows 7
On Win2K, XP and Win2K3 the console user is logged on in Session 0, the same session the services live in. If a service is configured as interactive, it'll be able to show the UI on the user's desktop.
However, on Vista, no user can be logged on in Session 0. Showing UI from a service there is a bit trickier. You need to enumerate the active sessions using WTSEnumerateSessions API, find the console session and create the process as that user. Of course, you need also a token or user credentials to be able to do that. You can read more details about this process here.
I think as long as you have only one user logged in, it will automatically display on that user's desktop.
Anyway, be very careful when having a service start an exe.
If the write access to the folder with the exe is not restricted, any user can replace that exe with any other program, which will then be run with sytem rights. Take for example cmd.exe (available on all windows sytems). The next time the service tries to start your exe, you get a command shell with system rights...
If you launch a GUI from your service it will show up on the currently active desktop.
But only if you adjusted the service permissions: You need to allow it to interact with the desktop.
Important Services cannot directly interact with a user as of Windows Vista. Therefore, the techniques mentioned in the section titled Using an Interactive Service should not be used in new code.
This is taken from : http://msdn.microsoft.com/en-us/library/ms683502(VS.85).aspx
Related
I'm using the _spawnl() function for launching a C++ native application from the main Service function (SvcMain), but the application never gets to run.
Is there any trick to launch applications that interacts with the user?
It runs, you just cannot see it. You have to use CreateProcessAsUser() instead of _spawnl() so the new process runs in a specific user's session, not in the service's own session. In Vista and later, services run in their own isolated sessions (Session 0 Isolation), which users cannot see or interact with. A common solution is to use WTSGetActiveConsoleSessionId() and/or WTSEnumerateSessions() to find the desired user session, then use WTSQueryUserToken() to get a token hanlde can be used with CreateEnvironmentBlock() and CreateProcessAsUser(). Also, when providing a STARTUPINFO to CreateProcessAsUser(), set the lpDesktop field to "WinSta0\\default" (the user's default desktop that they can interact with after logging in).
I am writing a service application that will run with local system credentials. I will need to know from my service if the Windows logon screen is displayed at any particular time. Is there any way to do this?
PS. The screens that can be brought up by locking the workstation:
Or by trying to switch the user:
Or after a Ctrl+Alt+Del:
PS. I need this to run on Windows XP and up.
EDIT: The only viable solution that I came up with so far is to see if LogonUI.exe process is running. The issue with this approach is how to distinguish between the actual system logon process and any other process that has that image name?
As described in the comments you are trying to detect whether or not a process in an interactive desktop session should show a message box. There being no point doing so if the interactive session is not active.
In which case I believe that your proposed solution is the wrong one. Instead you should register for session change notifications by calling WTSRegisterSessionNotification. When you do this you'll get sent WM_WTSSESSION_CHANGE messages that allow you to keep track of the current state.
Note that you do this in your desktop app rather than the service. The service still sends its messages to the desktop app. But the desktop app now knows whether or not it is worth showing them.
Update
Remy suggests a better way in the comments:
And if a separate app is being used, there is no reason to detect session changes at all, that app can simply check if its currently assigned workstation/desktop is the currently interactive workstation/desktop instead, comparing GetThreadDesktop() to OpenInputDesktop(), for instance.
All such screens are presented on a separate desktop. You may try to enumerate the user's desktops and compare it with the current (I am not sure the service in session 0 - Vista and up - can do that; if not, spawn a helper process in the user session). This however may give a false positive if an UAC desktop is up. Another corner case is a userless situation (right after boot before any user looged on).
There are several states in the windows.
Logged-Off State
When Winlogon is in the logged-off state, users are prompted to identify themselves and provide authentication information. If a user provides correct user account information and no restrictions prevent it, the user is logged on and a shell program (such as Windows Explorer) is executed in the application desktop. Winlogon changes to the logged-on state.
Logged-On State
When Winlogon is in the logged-on state, users can interact with the shell, activate additional applications, and do their work. From the logged-on state, users can either stop all work and log off, or lock their workstations (leaving all work in place). If the user decides to log off, Winlogon will terminate all processes associated with that logon session and the workstation will be available for another user. If, instead, the user decides to lock the workstation, Winlogon changes to the workstation-locked state.
Workstation-Locked State
When Winlogon is in the workstation-locked state, a secure desktop is displayed until the user unlocks the workstation by providing the same identification and authentication information as the user who originally logged on, or until an administrator forces a logoff. If the workstation is unlocked, the application desktop is displayed, and work can resume.
reference: https://msdn.microsoft.com/ko-kr/library/windows/desktop/aa380547(v=vs.85).aspx
p.s. registering a secure attention sequence (SAS, CTRL+ALT+Delete) is included in Workstation-Locked state
Similarly, there are several desktop types on windows.
Winlogon desktop
Application desktop(=Default desktop)
Screensaver desktop
Secure desktop
I recommend you read this:
https://msdn.microsoft.com/ko-kr/library/windows/desktop/aa375994(v=vs.85).aspx
I don't know my answers are what you want... but I hope it helps in some ways.
I need a certain process to be constantly running in every user’s computer. If that .exe is killed, I must be able to restart it and send an alert.
I immediately thought of building a Windows Service as the ideal solution, but I am facing a problem:
The process started by that service needs to be able to interact with the user, e.g. be able to show him a GUI.
my application also sets a keyboard hook in order to monitor the user's typing rhythms, and when I start the .exe from a service, that information is not accessible.
From the service I am able to launch the process "as the user" (using the LogonUser and CreateProcessAsUser functions), but still can’t see the GUI.
Is this possible? If not, what can I use to achieve the desired functionality?
tia
By default the GUI .exe will be run in the service session, which is separate from the interactive session of the user. You need to look into techniques for building an interactive service.
I have a C++ Win32 application that was written as a Windows GUI project, and now I'm trying to figure out to make it into a Service / GUI hybrid. I understand that a Windows Service cannot / should not have a user interface. But allow me to explain what I have so far and what I'm shooting for.
WHAT I HAVE NOW is a windows application. When it is run it places an icon in the system tray that you can double-click on to open up the GUI. The purpose of this application is to process files located in a specified directory on a nightly schedule. The GUI consists of the following:
A button to start an unscheduled scan/process manually.
A button to open a dialog for modifying settings.
A List Box for displaying status messages sent from the processing thread.
A custom drawn window for displaying image data (the file processing includes the creation and saving of images).
A status bar - while a process is not running, it shows a countdown to the next scheduled scan. During a scan it also provides some status feedback, including a progress bar.
WHAT I'M SHOOTING FOR is a service that will run on boot-up and not require a user to login. This would consist of the scheduled file processing. However, when a user logs in I would still like the tray icon to be loaded and allow them to open up a GUI as I described above to monitor the current state of the service, change settings, start a scan manually, and monitor the progress of a scan.
I'm sure that I have seen applications like this - that function as a service even when I'm not logged in, but still give me a user interface to work with once I do log in.
I'm thinking that instead of having a single multi-threaded application that sends messages to the GUI thread from the processing thread, I need two applications - a Service to perform the processing and a GUI application to provide visual feedback from the Service and also send messages to the Service (for example, to start a scan manually). But I am new to Windows Services and have no idea how this is done.
It is also possible that I'm completely off base and a Service is not what I'm looking for at all.
Any help / ideas / suggestions would be greatly appreciated! Thank you.
You can't do this as a service.
You'll need to make your Windows Service as a normal service application. This will startup on system startup, and run the entire time the system is up.
You'd then make a completely separate GUI application, which "talks" to the service. This can be set to run when a user logs in, in the user's account.
In order to make them "talk" to each other, you'll need to use some form of IPC. Since these run on the same system (but in different accounts, typically), named pipes or sockets both work quite well.
There is a simple way of doing it.
You can’t have the service access any user’s session (session 1,2,3..) since services are isolated and can access session 0 only. This is a change from 2011.
You should write a win32 program to be launched by your service per each user who logs in using https://msdn.microsoft.com/en-us/library/windows/desktop/ms682429(v=vs.85).aspx
The service can continue performing any task that isn’t user specific.
I'm am developing a Firefox extension which interfaces with an underlying Windows service (which I have already made).
During the development so far I encountered one bug in the installer program (which installs the FF extension AND the service). This was due to the security model on Vista requiring elevated privileges to be able to install and start the service. I adjusted the installer and now it installs fine (just with additional Vista'esque warning dialogs being displayed to end-users - which I can live with !)
I am now in the process of developing an XPCOM component that will install along with the XUL stuff I have already made. There will be a XUL javascript interface to the XPCOM which will try to do things like stop and start the service (e.g when user-configuration data is changed).
My question: Since FF will normally be run under a user account, will I run into any difficulties on Vista or other Windows flavors trying to start or stop my own service via XPCOM?
(When users run the installer I don't mind security dialogs popping up in Vista. But I certainly don't want this to happen whenever they try to change their info in the XUL interface.)
What is the correct way to go about this?
Yes, if your service is running as an Administrator then the Firefox process, running as a normal user will not be able to start or stop it. However, it appears that you can use the "sc" command to set access controls on your service from your installer, which means you can allow non-admin users to start and stop your service.
You'll need to use "sc sdset", which is documented (lightly) here:
http://technet.microsoft.com/en-us/library/cc742037%28WS.10%29.aspx
However, to use that, you'll need to read up on the "Security Descriptor Definition Language", which looks kind of complicated:
http://msdn.microsoft.com/en-us/library/aa379567%28VS.85%29.aspx
This blog entry appears to have some human-readable information on it:
http://blogs.dirteam.com/blogs/jorge/archive/2008/03/26/parsing-sddl-strings.aspx