In Windows Server 2003, how I can check if my program is running in local console ("on the screen of the server machine") instead of remote session?
I'm using Delphi Win32, so any Windows API based method should work..
Wouldn't the session number tell you this ?
ProcessIdToSessionId (GetCurrentProcessId(),&dwSessionNum)
You'd have to check the OS version as well, using GetVersionEx: for everything up to XP/Server 2003 session 0 is local (service or interactive console), anything higher is virtual. For Vista/2008 session 0 and 1 are both local (0 is service, 1 is console), everything else is virtual.
I'm guessing your Delphi units would declare the session number as var, so you wouldn't need the ampersand.
WTSGetActiveConsoleSessionId() should return the ID of the session attached to the console. You can then compare that session id with your application's current session ID to determine whether you are running on the console or not. Vista (not sure about Windows Server 2008) does not necessarily give the console session the ID of 1 (Fast User Switching, anyone?).
For me, ProcessIdToSessionId returned 0 both when run directly at the physical console and when logged in to the administrative session (mstsc /admin).
However, when you login via RDP, Windows (XP Pro in this case) creates a new session which it shows on the physical console which just has the "this computer is locked" display. WTSGetActiveConsoleSessionId returns the session id for that second session which in my case was 2.
So even though your app is running on the console, there are now two console sessions and your app is not running on the active one. In my code I compare session id against 0 instead.
Brian is correct, I have since encountered Vista reporting a session id of 2 for an interactive console, despite the fact that Fast User Switching was not in use. Of course, this may be just be a bug :-)
Related
Assume the following scenario:
I log on terminal server with RDP (Windows Server 2012 R2 or 2016)
Another user connects to my session with "mstsc.exe /shadow" command.
I get the message to confirm this access, and I agree.
Then, after a while I would like to check if my session still being shadowed.
Is there any way to perform this check? Any command, Win32 API, WMI query?
So far, I was only able to find out that rdpsaproxy.exe program is started in shadowed session. That is almost enough, but this program also keeps running when user denies access when prompted to accept initial shadowing request. So detecting presence of rdpsaproxy in check session is not enough to say that somebody is watching me.
You could bind a notification task to the events of Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational event log:
20503 - shadow watching started
20504 - shadow watching stopped
20506 - shadow control started
20507 - shadow control stopped
Delphi XE app running on Windows 2012 Server. How do I limit the user's permissions when they open Adobe Viewer using ShellExecute. As it stands now, the uses are not permitted to see the drivers on the server. However, when the user opens a pdf from the application, the permissions revert back to admin, which allows them to see and access the drives.
Are there settings within ShellExecute that can apply the proper permissions based on the user login credentials?
When you create a process using ShellExecute, the new process runs under the credentials of the parent process. So it would seem that the process with is calling ShellExecute has more rights than you wish to grant to the process that is started by ShellExecute.
One way to solve the problem would be to call ShellExecute from a process running under the desired credentials. There may be other ways to solve it, but without any knowledge of your network security configuration, it's unlikely that we can give you much more specific advice.
I'm using the following API call to determine the name of the remote client in a Terminal Server session:
ret = WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION,
WTS_INFO_CLASS.WTSClientName, buffer, bufferLen)
Usually, when the application is not running in a terminal server session, the call succeeds (ret != 0) and buffer just returns a null pointer. So I figured that this was the expected behavior.
On one customer's machine, however, the function started to fail (ret == 0) and GetLastError returns 5: Access Denied. (As usual, the customer claims that his system configuration did not change in any way.)
So, my questions are the following:
What is the expected behavior when querying the WTSClientName on a non-terminal-services machine (such as, e.g., a "regular" Windows 7 PC)?
What could be the reason that this error code is returned? Note that, on our test machines, the function call always behaves as expected (success and empty buffer), even if the user does not have administrative rights.
I don't know if this is relevant, but we are able to reproduce this problem (error 5) by calling the function from inside a web application. This, however, is not the case in this case (it's a regular Windows application).
I agree with you and also suppose that some from system configuration at the client are changed. To find out which one from the changes in file system or in registry are important for WTSQuerySessionInformation you can try to use Process Monitor.
You can also ask your customer to download the tool, start the Process Monitor and then start your test program used WTSQuerySessionInformation, save the log and post it to you. I suppose, that you will see some "access denied" errors in the log. I hope it will help you to find the problem in the configuration of the client's computer.
I don't know the expected behavior but I encountered error code 5, access denied, when calling WTSEnumerateSessions on Win7. Set DWORD HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\AllowRemoteRPC to 1 and issue was immediately fixed.
This is happening when you call it from web application becasue the web server is running under the (session 0) of windows.
read more about session 0
From the Microsoft website (see msdn.microsoft.com/en-us/library/ms683502(VS.85).aspx) it clearly says "Services cannot directly interact with a user as of Windows Vista".
So I decided to test this by using "psexec -s cmd.exe". As far as I know, "psexec" creates a service in order to open a command prompt. Needless to say it worked. I then decided to use "EnumWinSta GUI" in combination with psexec to switch to the winlogon desktop. To my surprise, I could even start "cmd.exe" on this desktop. Does this mean a new process created from a service can be interactive?
Or is it because psexec does some kind of black magic? If so how does it do it?
I am trying to display a full screen window from a service into the winlogon desktop object in Vista as well as XP.
Code running within a service cannot directly interact with an interactive session.
However, code running as a service with sufficient privileges can create a new process running within a specific user's desktop - getting the interactive session's user's token and calling CreateProcessAsUser, for example.
You can use WTSGetActiveConsoleSessionId to get the active console session, the session of the user who is actually on the machine. WTSQueryUserToken can then be used to get the token.
Your service can also use session change notifications in its handler function to see when users logon/logoff, unlock their session, and so on.
From a Windows Service running on a Terminal Server (in global space), we would like to be able to start up a process running a windows application in a specific user's Terminal Server sessions.
How does one go about doing this?
The Scenerio: the windows service starts at boot time. After the user has logged into a Terminal Server user session, based on some criteria known only to the windows service, the windows service wants to start a process in the user's session running a windows application.
An example: We would like to display a 'Shutdown in 5 minutes' warning to the users. The windows service would detect this condition, and start up a process in each user session that starts the windows app that displays the warning. And, yes, I know there are other ways of displaying a warning dialog, this is the example, what we want to do is much more invasive.
You can use CreateProcessAsUser to do this - but it requires a bit of effort. I believe the following steps are the basic required procedure:
Get the user's session (WTSQuerySessionInformation).
Get a token for that user (WTSQueryUserToken).
Create a duplicate token for your use (DuplicateTokenEx).
Use the token to create an environment block (CreateEnvironmentBlock).
Launch the application with CreateProcessAsUser, using the block above.
You'll also want to make sure to clean up all of the appropriate handles, tokens, etc., after you've launched the process.
Really late reply but maybe somebody will find this helpful.
You can use PsExec to launch an application on a remote (or local) server inside a specified session by using the following command:
psexec \\COMPUTER_NAME -i SESSION_ID APPLICATION_NAME
Where SESSION_ID indicates the session id in which to launch the application.
You will need to know what sessions are active on the server and which session id maps to which user login. The following thread provides a nice code sample for this exact problem: How do you retrieve a list of logged-in/connected users in .NET?
Late reply but in the answer above DuplicateToken is not necessary since WTSQueryUserToken already returns a primary token.