I want to expand user specific environment variables. I have API for that "ExpandEnvironmentStringsForUser". My code is running in context of service. I want to fetch currently logged in user. Whenever I use GetUserName API it returns "SYSTEM".
My problem is I want to expand %temp% in user specific mode and not in system mode.
Is there any way to get currently logged in user when my code is running in service context?
If your program is running as a service, then there isn't "a logged-in user". The whole notion of multi-user systems makes such a concept meaningless. There could be any number of users logged in, and it is impossible for your program to guess which one you wanted it to pretend to be running under.
Your question is like asking "of all my family members, in whose bedroom is my car currently parked?" when in fact the car is safely and sanely sat outside in the driveway.
You can use the qwinsta command (part of Terminal Services) to obtain a list of currently logged-in users, and do something with that; it'll have absolutely nothing to do with your service, but on some Windows systems that allow only one interactive session at a time (for licencing reasons), it'll be the only one marked Active:
C:\Users\tomalak>qwinsta
SESSIONNAME USERNAME ID STATE TYPE DEVICE
services 0 Disc
>console tomalak 1 Active
That's a little hacky, though; typically you would have a little user-space application that can talk to the back-end service, and do all the user-specific shenanigans in the application.
Related
Is it impossible to access the mapped network drive( mapped in user session) from service after impersonating the current user by using ImpersonateLoggedOnUser Windows API?
Yes, this is impossible. Drive mappings are only established during an interactive logon. The ImpersonateLoggedOnUser function does not impersonate the user's entire logon session, just their security context. This is only one of the many things that cannot be done using impersonation.
I suppose you might be able to do this by duplicating the user's login token (obtained from one of their interactive processes), and then using that to call the CreateProcessAsUser function. You would then launch a process that would work with the mapped network drive(s). I'm not absolutely certain that this will work, as I've never done it, but it seems theoretically possible.
Of course, it begs the question of why you need to follow such a circuitous route. It would be eminently more sensible to just run your code in the user's interactive process to begin with, as a standard Windows application.
This is not something that a service is designed to do. Services do not support mapped network drives. If you want to access a network resource from within a service, you should just use the UNC path.
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
I am looking for a method to use as an alternative to disabling UAC to keep application persistence throughout the lifetime of the system.
My application runs every time the system starts up, and it requires elevated privileges, so when UAC is enabled it asks the user whether or not to run my application, every time the system is rebooted. This is very tedious and can become annoying if it happens every time. If UAC is disabled this warning no longer appears but of course that is very harmful to the user as it could lead to threats on their computer.
My question is; In C++ how can I programmatically allow file/application persistence throughout any event on the users' PC just for my application without getting the UAC warnings each time!
I am looking for ANY possible method, an exploit, a bypass method, anything, I'm really desperate at the moment as I've been stuck with this program for several days now and I'm just 99.9% done my project. I really need to get this through. THANK YOU SO MUCH FOR ANY ADVICE you may offer me!
The first step is to determine whether your program really needs admin privilege at all. Sometimes a program only runs with admin privilege, but for trivial reasons: a log file is being generated in the wrong place, for example, or a file that should be being opened for read-only access is being opened for full access. If that's the case you can fix the problem and avoid any further structural changes.
Secondly, ask whether your program needs admin privilege all the time, or only when the user performs certain actions. In the latter case, you should probably only elevate when it becomes necessary to do so; as well as meaning that the user does not need to approve the program launch on every reboot, it also helps protect the user from making an administrative change without intending to. This is particularly relevant if UAC is configured to require a password each time.
Thirdly, ask whether your program really needs a user interface. If not, then it should be a system service.
If your program really does need admin privilege all the time, and really does need a user interface, then you need to separate it into two parts, one containing the user interface and one containing the functionality that requires elevated privilege.
The user interface part should be a program that runs whenever a user logs in, just as your program does now. The elevated privilege part should be a system service.
The primary logic might belong in either part, or might also need to be split into two; it depends entirely on the context. (The system service does need to contain enough logic to ensure that the the privileged operations it is performing are safe and appropriate. It can't simply do anything the user interface part tells it to.)
These two parts can interact using whatever form of inter-process communication and/or synchronization is most convenient. You do need to be aware that they will be in different Remote Desktop sessions; for example, if you create an event object for synchronization the name must start with the Global\ prefix.
You will need to consider that more than one user may be logged in at the same time, either via Switch User or because the machine is a Remote Desktop server. This may mean that the service component needs to support multiple simultaneous clients, which affects your choice and implementation of IPC. Alternatively, the user interface component needs to detect that another instance is already running, and wait until that instance goes away before attempting to connect.
You will also need to consider how the program should react when the logged-in user does not have administrative privilege. At the moment such a user can't run your program at all, probably making the prompts even more annoying than they are to an admin user! If it is OK for the program to work as normal for a non-admin user then you don't need to do anything special. If the program should not work for a non-admin user, or if some of the functionality should be restricted, then (a) the GUI component needs to behave accordingly, by, e.g., exiting silently; and (b) the service component needs to check the context in which the GUI component is running. It is not enough for the GUI component to do the check, because the user can trick it if he or she wishes to; the service component must check too.
The easiest way to do that is probably to use GetTokenInformation with the TokenElevationType option; if the token type is TokenElevationTypeLimited or TokenElevationTypeFull, the user has administrator privilege. If the token type is TokenElevationTypeDefault, there is no split token; either the user is not an administrator, is the local Administrator account, or UAC is turned off; in this case, use CheckTokenMembership to check whether the user is in the Administrators group or not.
In some cases, it might also be sensible for certain tasks to require UAC approval, even if other tasks do not. Such tasks need not involve the service component; the GUI component can elevate itself, with the user's consent, to perform them.
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 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