Credential provider usage scenario: CPUS_UNLOCK_WORKSTATION removed from Windows 10 - c++

I'm developing a custom credential provider and need to know at runtime if the scenario is a login or an unlock of the session. For this, I check the CREDENTIAL_PROVIDER_USAGE_SCENARIO returned by the SetUsageScenario of the ICredentialProvider interface.
On Windows 10, independently if I'm at login or when the session is locked, I always get CPUS_LOGON as usage scenario, while on previous version of Windows, CPUS_UNLOCK_WORKSTATION was returned when the session was locked and CPUS_LOGON at the login.
So it seems that changes appeared since Windows 10 that are not reported on MSDN.
Is there any other way to detect if the usage scenario is a session locked?

I am currently investigating the same issue and may have a work around until Microsoft can update the documentation.
Although I still receive a CPUS_LOGON, we are still inside the same session as the locked user. By using the function WTSQuerySessionInformationW, you can verify that there is currently a user logged in to the current session. From there, you can proceed as if you were in a CPUS_UNLOCK_WORKSTATION usage scenario.
UPDATE (1/18/2016): It seems Microsoft has finally updated their documentation on this issue. See the excerpt below from the CREDENTIAL_PROVIDER_USAGE_SCENARIO documentation:
Starting in Windows 10, the CPUS_LOGON and CPUS_UNLOCK_WORKSTATION
user scenarios have been combined. This enables the system to support
multiple users logging into a machine without creating and switching
sessions unnecessarily. Any user on the machine can log into it once
it has been locked without needing to back out of a current session
and create a new one. Because of this, CPUS_LOGON can be used both for
logging onto a system or when a workstation is unlocked. However,
CPUS_LOGON cannot be used in all cases. Because of policy restrictions
imposed by various systems, sometimes it is necessary for the user
scenario to be CPUS_UNLOCK_WORKSTATION. Your credential provider
should be robust enough to create the appropriate credential structure
based on the scenario given to it. Windows will request the
appropriate user scenario based on the situation. Some of the factors
that impact whether or not a CPUS_UNLOCK_WORKSTATION scenario must be
used include the following. Note that this is just a subset of
possibilities.
The operating system of the device.
Whether this is a console or remote session.
Group policies such as hiding entry points for fast user switching, or interactive logon that does not display the user's last name.
Credential providers that need to enumerate the
currently user logged into the system as the default tile can keep
track of the current user or leverage APIs such as
WTSQuerySessionInformation to obtain that information

If you turn fast user switching off, you will get the CPUS_UNLOCK_WORKSTATION messages upon locking. Otherwise you will only receive CPUS_LOGON. If you manually lock the PC using the windows API call from code to lock with fast user switching turned on, it will lock sending CPUS_UNLOCK_WORKSTATION and then immediately log off sending CPUS_LOGON.I Hope this helps, i don't have the reputation score to post an answer of my own so i edited this comment.

You might try SENS (System Event Notification Service). This is a Microsoft provided notification service.
https://msdn.microsoft.com/en-us/library/windows/desktop/cc185680(v=vs.85).aspx
It has different events for logon/logoff and screen lock/unlock notifications. It uses a COM+ interface. I am not familiar with the requirements of credential providers so I don't know if the service will run within the context you require or if the timing of the event arrival will meet your needs but it is something you might investigate.

Of all the answers, Justin's one is the more informative one, but nobody provides a workaround to properly restore the Windows7 behavior. Scott's answer mentions turning off Fast User Switching, but that turns off a feature that is available in Windows7, making it not a proper workaround. After carefully reading all the information available and several attempts, I found the following policies that allows only the previous logged user to unlock the machine, hence forcing the LogonUI framework to issue CPUS_UNLOCK_WORKSTATION scenario, but still allowing fast user switch:
Windows Registry Editor Version 5.00
; Computer Configuration -> Windows Settings -> Security Settings ->
; Local Policies -> Security Options "Interactive logon: Do not display last user name"
; Set to "Enabled": asks to unlock the machine only to currently logged user
; https://learn.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/interactive-logon-do-not-display-last-user-name
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System]
"dontdisplaylastusername"=dword:00000001
; Computer Configuration -> Administrative Templates -> Windows Components ->
; Windows Logon Options -> "Sign-in last interactive user automatically after a system-initiated restart"
; Set to "Enabled": Prevents last signed user to log in and lock automatically
; after a restart
; https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/component-updates/winlogon-automatic-restart-sign-on--arso-
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System]
"DisableAutomaticRestartSignOn"=dword:00000001
; Similar in bevahior to "dontdisplaylastusername" but also disables Fast User
; Switching, which was available in Windows7
; https://learn.microsoft.com/en-us/windows/client-management/mdm/policy-csp-windowslogon#windowslogon-hidefastuserswitching
;[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System]
;"HideFastUserSwitching"=dword:00000001

Related

ETW how to survive a reboot

Using C++/Win32 API I create myself an event trace session. My application must supported NT5 thus I can't newer the newer APIs.
I am using the circular mode flags and real time flags.
I have everything working apart from one snag, when I reboot the machine the ETW session isn't persisted, my service starts up and recreates the ETW session (as the reboot has wiped it) which then causes the log file to be overwritten.
According to MSDN I must use the "global" logger on NT5 of which there can only be one, or an "AutoLogger" on NT6 of which there can be many. However MSDN says:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363687(v=vs.85).aspx
The AutoLogger sessions increase the system boot time and should be
used sparingly. Services that want to capture information during the
boot process should consider adding controller logic to itself instead
of using the AutoLogger session.
Sounds like overkill for what I'm trying to do. Indeed my service does contain the "controller" logic itself.
So how do I get ETW to keep my trace session for the next reboot? Or alternatively how do I re-create my ETW session on the next reboot without overwriting the ETW file if its already there?

How to tell that the logon screen is currently displayed?

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.

Is it possible to display my window over a Windows logon screen?

I'm writing a service/user-mode application that may send the system into sleep after a certain customizable period of inactivity. The user-mode process may require to display a user message/warning before performing a power operation. This works great if a user is logged in, but if the workstation is locked, a user sees a display like this:
So I'm curious if it is possible to display my own window (overlay) above such a logon screen?
The only supported API for this, since Vista, is the credential provider. The documentation can be found over on MSDN.
I found this post that might be exactly what I need. I'll post later when I try it out...

Volume changes without creating notification for IAudioEndpointVolume

I'm have written a C++ application that is running as a Windows service to limit the volume of a Windows 7 computer. The user can specify different rules for different days and times and the service will smoothly change the volume. To implement this I use the IAudioEndpointVolume interface. In general it works like intended...
However, there exists a strange behavior I cannot explain yet. When switching users the volume suddenly drops but it does not generate a notification as one would expect. What is also strange is that the sliders in the SndVol.exe show the correct value for the volume.
Because of the missing notification my program cannot react to this change and as a result it cannot perform its intend anymore.
I have discovered that the volume will switch back to its correct volume again if I move the volume slider a bit. Of course this generates a notification that will be handled by my service. My service will then force the correct volume.
I don't understand why the volume changes without being visible in SndVol.exe and without creating a notification. Switching back to the first user account does not solve the problem. Even after logging out the volume is still at the wrong level.
As far as I have seen the documentation about the IAudioEndpointVolume interface does not mention anything about different user session.
Any ideas on what might cause this problem or what I could try to fix it?
Your service runs in session 0, the isolated session that prevents malware from exercising shatter attacks. The user's desktop runs in another session, there can be multiple. The WASAPI documentation is silent about exactly how an audio session gets mapped across Windows sessions. You have a very strong hint that it doesn't from the way it behaves.
There are ominous words in the section that talks about grouping parameters. A construct that primarily exists to allow Sndvol to identify processes that share the same volume control. It quotes Explorer as an example, a process that can be started more than once but still has a single volume control. A process that doesn't want to share uses session identifier GUID_NULL to select the default session in IAudioSessionControl::SetGroupingParam() or simply omits the call altogether since that's the default.
And the behavior of Sndvol, it only displays volume controls for the processes that run in the desktop session. You can't see the processes in another desktop session. Giving a very strong hint that audio session GUID_NULL is specific to the session in which it got created.
So quite unlikely that you can find a workaround for it as long as you do this with a service.
Instead, consider running your program as a normal windowless process that runs in the user's desktop session. Getting started by the Run registry key or a Startup folder shortcut or the task scheduler.
Well, after some time I am now quite confident that the volume change is caused by the 3rd party driver we are using. This driver has it's own volume control mechanism. I do not experience the change anymore after just starting the drivers' control GUI. Even after a restart the problem seems to be fixed. However, after some time it gets broken again for a reason I cannot figure out. But this only happened because some security settings prevented the drivers' control GUI to start when logged in as non admin. I fixed this now and expect everything to work now.
Furthermore it looks like that all user sessions share the same volume control. That means if I change the volume with SndVol in one user session the same change happens in the other user session. My service receives notifications for all these changes. So it looks like that I did not receive a notification when switching between users because the change was caused by the driver's control GUI starting when logging in as administrator. But this change happened in the driver, a lower layer, so that Windows is not aware of the change.
The driver we are using is the kX Audio Driver.

How can a Windows service execute a GUI application?

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