Remko Weijnen's Blog (Remko's Blog)

About Terminal Server, Citrix, Delphi and other stuff

Archive for the ‘Terminal Server’ Category

Well it took some time but I patched Terminal Server for Windows 2008 to allow unlimited sessions in Remote Administration mode.

This patch is for 32 bit English version. In order to install it you need to perform the steps below. Before you start please check if using this patch is allowed according to your country’s law and your license agreement.

(more…)

As you might know Windows 2003 Server accepts at most 2 concurrent Terminal Server sessions (and 1 console session) in Remote Administration mode (which is the default). Of course if you switch to Application Mode you can have an unlimited number of sessions but this requires licenses and a license server.

When Terminal Server creates a new session it checks if the new session is either a console session or a help assistant session and if not it allocates a license. The function that performs this check is called CRAPolicy::Logon (more…)

There are several patched terminal server dll’s floating around in the net to allow multiple concurrent Terminal Server session on Windows Vista with Service Pack 1. But they all have the same limitations:

It’s not possible to start a session to Localhost, this is because the Terminal Server client does a check to see if you are running Personal Terminal Server (Vista/XP) and denies Localhost or 127.0.0.1 if true (127.0.0.2 works though).

It’s not possible to start multiple sessions with the same user. The patch for Vista RTM did allow for this but in Service Pack 1 some Terminal Server code has moved to the Local Session Manager (lsm.exe) so we need to patch this file as well.

Offcourse we need to patch Terminal Server to allow unlimited session on Vista as well.

VPatch files are in the download link below.

Vista SP1 Patches (3703)

Terminal Server Ping Tool

A while ago I included a new undocumented API into my JwaWinsta unit which is called WinStationServerPing. This API “pings” a Terminal or Citrix server and verifies that Terminal Server is up and running. It is not the same as a regular networking ping! This API actually makes a connection to a (remote) Terminal Server and verifies that Terminal Server runs and accepts connections.

I wrote a small cmdline tool that uses this API to ping a Terminal Server which can be used to quickly determine if a Terminal Server is up and running. I named it WTSPing.

So how does it work? Open up a command prompt (Start -> Run -> cmd) and type WTSPing /? to see the help:

(more…)

Several months ago I wrote about encrypting and decrypting RDP passwords. I left one thing open: encrypting the password up to the full 1329 bytes as mstsc does.

Many people were curious about it so I hope the answer is not a disappointment because it’s actually really simple (but I took me a while to figure that out nonetheless). In what I figure is an attempt to hide the password length mstsc always fills up the password with zeroes until it has 512 bytes length.

Then the password is encrypted like I described earlier which gives us a 1328 bytes password hash. So we have one mystery left, how to reach the 1329 bytes size which still is a strange value since the password is in Unicode which takes 2 bytes per char (so the size should be even).

As it turns out, mstsc just adds a zero!

RDP v2 Screenshot

Remote Desktop Password Encryption & Decryption Tool (2152)

In a previous article I wrote about changes in utildll in vista that breaked compatibality for Terminal Server. Even though release notes for Service Pack 1 don’t indicate changes or fixes in this area my testing shows that Microsoft has taken over the Windows 2008 implementation of utildll to Vista.

This is a good thing, because applications depending on utildll work again. I have updated JwaWinsta for SP1, all Vista versions of the utildll functions are renamed to VistaRTM and all Safe functions were updated to check for SP1. This means that the Safe functions can be used on all OS versions and Service packs! You are strongly advised to use only the Safe functions.

Some observations with SP1: 

  • I quickly tested TSAdmin as well and it seems to work again, only noticable flaw is that the console sessions returns an idle time of 17642 days (Reported Last Input Time is 01-01-1601 but utildll’s ElapsedTimeString function doesn’t account for dates this long in the past).
  • WTSApi32.dll contains some new functions like WTSStartRemoteControlSession and WTSStopRemoteControlSession (which are wrappers to WinStationShadow).
  • The WTSWaitSystemEvent bug I wrote about earlier is still present. I advise to check for winsta.dll version >= 6.0.6000.20664 in code when using this API and advise user to install the Hotfix.

Update: I just tried to install hotfix KB941561 but this fail with the error: The update does not apply to your system. If you do want to get this bug fixed you need to manually replace winsta.dll (take ownership and set permissions to full control).winsta.dll from hotfix KB941561 (X86) (310)

For my Terminal Server unit in the Jedi Security library I use 2 TObjectList descendants to hold a list of Terminal Server Sessions and Processes. Consider the sample below which connects to a server and enumerates all sessions:

var
  ATerminalServer: TJwTerminalServer;
  i: Integer;
begin
  ATerminalServer := TjwTerminalServer.Create;

  ATerminalServer.Server := ‘TS001′;

  try
    if ATerminalServer.EnumerateSessions then
    begin

      // Now loop through the list
      for i := 0 to ATerminalServer.Sessions.Count1 do
      begin
        Memo1.Lines.Add(ATerminalServer.Sessions[i].Username);
      end;

    end;
  except
    on E: EJwsclWinCallFailedException do
    begin
      // Handle Exception here
    end;
  end;

  // Free Memory
  ATerminalServer.Free;
end;

In the sample I loop through the sessions with a for loop. Even though Delphi supports the for in loop since Delphi 2005 it’s not possible to use this in TObjectList descendants, so we cannot use this:

// Now loop through the list
for Session in ATerminalServer.SessionList do
begin
  Memo1.Lines.Add(Session.Username);
end;
 

To make this possible we need to implement GetEnumerator and an Enumerator class:

TJwSessionsEnumerator = class
private
  FIndex: Integer;
  FSessions: TJwWTSSessionList;
public
  constructor Create(ASessionList: TJwWTSSessionList);
  function GetCurrent: TJwWTSSession;
  function MoveNext: Boolean;
  property Current: TJwWTSSession read GetCurrent;
end;

constructor TJwSessionsEnumerator.Create(ASessionList: TJwWTSSessionList);
begin
  inherited Create;
  FIndex := -1;
  FSessions := ASessionList;
end;

function TJwSessionsEnumerator.GetCurrent;
begin
  Result := FSessions[FIndex];
end;

function TJwSessionsEnumerator.MoveNext: Boolean;
begin
  Result := FIndex < FSessions.Count1;
  if Result then
    Inc(FIndex);
end;
 

Now we add a function with the name GetEnumerator in the SessionList class:

function TJwWTSSessionList.GetEnumerator: TJwSessionsEnumerator;
begin
  Result := TJwSessionsEnumerator.Create(Self);
end;
 

And that’s really all!

TSAdminEx Progress

I just wanted to show some of the progress that I made in development of TSAdminEx. I thought the best way would be to show some screenshots. Which reminds me I installed a nice Javascript to enlarge the thumbnails, click to see it…

Edit: A beta is ready!

This screenshot shows TSAdminEx after startup. In the Left Treeview you can see the This Computer, Favorites and All Listed Servers icon. On Startup all available domains are enumerated.
Here you see the Users tab. If you move the mouse over some columns you can get extra info in the hint. In this hint you get the actual shadow permissions of the highlighted session.
This is the Sessions tab where extra details of a session are shown. By default you can see sessions statistics such as Incomingbytes and Outgoingbytes, this makes it easy to identify sessions that have much traffic.Interesting detail is that the Remote Address column lists the real ip address that is connected to Terminal Server! Hovering the mouse also shows the port number.
Now the Process tab is my favorite! It lists far more details than TSAdmin and also some usefull columns that cannot be show with TSAdmin or any documented Terminal Server API!The Process Age columns shows how long the process is running. You can compare this with the CPU Time column to see how much CPU Time the process has allocated since startup.The Mem Usage shows the amount of physical RAM a process uses while the VM Size column shows the amount of Private Bytes (Virtual Memory) a process uses.
If you click on a domain in the Left Treeview, TSAdminEx will enumerate all Terminal Servers for that domain. You can continue using and even enumerate multiple domains, because enumeration is done from seperate threads!
If you select (highlight) a particular session the appropriate toolbar buttons are enabled or disabled automically indicating the actions that can be performed on the selected session.
And offcourse, an about dialog…

Hope you like it! Comments are open…

Using WTSWaitSystemEvent

If you develop an application for Terminal Server you might want to react on session events. This means that your application is notified when a user logs on, logs off or becomes idle. This can be done with the WTSWaitSystemEvent function. Implementing it is rather simple and could look something like this:

procedure TJwWTSEventThread.Execute;
begin
  while not Terminated do
  begin
    if WTSWaitSystemEvent(ServerHandle, WTS_EVENT_ALL, FEventFlag) then
    begin
      Synchronize(DispatchEvent);
    end;
    Sleep(10);
  end;
end;

Notice that you would probably do this from a seperate thread otherwise you will block the main thread. To stop waiting for Events you send a special event:

// unblock the waiter
WTSWaitSystemEvent(FServerHandle, WTS_EVENT_FLUSH, EventFlag);

Please note that there are at least 2 issues with this API, one with Windows 2000 and one with Windows Vista. On Windows 2000 events are reported twice for each actual event. Microsoft’s resolution?

The application should expect the event twice, and filter out the second occurrence.

Now how do we solve this? I would suggest introducing a small delay after an event trigger, this way you will probably not receive the duplicate event.

On Windows Vista there’s another issue: After you set the value of the EventMask parameter to WTS_EVENT_FLUSH in the WTSWaitSystemEvent function, no pending calls to the function return on a Windows Vista-based computer. Now what does this mean? It means that after sending WTS_EVENT_FLUSH the thread never responds! So there’s actually no nice way to end the thread, the only escape is a call to TerminateThread.

Microsoft does offer a hotfix, so my suggestion is a check on startup that will notify the user that he/she needs to install the hotfix. A version check can be done on winsta.dll, the version before the fix is 6.0.6000.16386. Hotfix version is 6.0.6000.20664. According to this article the fix will be included in Vista SP1.

References:

Have you ever tried running the Terminal Server Administration tool (aka TSAdmin) on Windows Vista? You would need it to remotely administer windows 2000/2003 Terminal Servers. If you try to run it you will get an Access Violation but why? I found the answer to this question today because I was testing my TSAdmin replacement on different Windows versions. Just like TSAdmin I use an (undocumented) function from Utildll.dll called ElapsedTimeString. It’s a very simple function that returns a formatted elapsed time string (as seen in the Idle time column from TSAdmin).

While my TSAdminEx ran fine on Windows XP, 2003 and even 2008 it would crash on Vista. Investigation showed that the stack was corrupted in the process of enumerating processes and sessions. Eventually I pinned it down to ElapsedTimeString but could not understand what went wrong. At least not until I investigated Utildll.dll version from Windows Vista. In what was probably an attempt from Microsoft to produce safer code they replaced wsprintfW by StringCchPrintfW. But StringCchPrintfW has an additional parameter (count of characters) so they introduced a new parameter to ElapsedTimeString. Now that’s not a smart decision as this directly breaks compatibility with software that uses this API, but they probably thought that it wasn’t issue since TSAdmin is not included with Vista (I don’t know of any other MS tool that uses this API).

But why doesn’t the Access Violation appear on Server 2008? Is this still using wsprintfW for string formatting? The answer is no, they also use StringCchPrintfW but use a fixed 15 character length. (so they “fixed” the issue).

That leaves you with 2 options if you still want to use TSAdmin on Vista:

  1. Patch TSAdmin or Utildll
  2. Use my TSAdminEx instead which also offers some extra functionality over TSAdmin (I hope to finish it soon, should you wish to beta test then leave a comment).

For now I’ll leave you with a screenshot (click to enlarge) of the current Beta version. As you can see it returns detailed information in the process tab like Memory Usage, Virtual Memory Usage, CPU Time and Process Age.

TSAdminEx Beta Screenshot

Profile

Recent Tweets

Views