The kernel object namespace and Win32, part 2

Last time, I talked about how the kernel object namespace intersects with the Win32 world as of how things stood in NT4 (and Windows 2000 when Terminal Server is disabled).

Although the object namespace model used in these operating systems worked well, some cracks began to appear in it with the introduction of Terminal Server as a mainstream product (and later, RunAs).

There are basically two problems that are imposed by Terminal Server:

  1. Many programs are designed to run as “singleton” programs, but in multi-session environments like Terminal Server, it is desirable to allow each session to run an instance of such programs. The classic way to enforce singleton behavior like this is to create a named kernel object at startup, and check to see if the object already existed before the program tried to create it. Without alterations to how the object namespace presented to Win32 functions, this would prevent singleton applications from working under Terminal Server.
  2. Drive letters and other “DOS Devices” symbolic links need to become “sessionized”, because the “glass terminal” (physical computer console) typically has things like COM1 or LPT1 pointing to physical serial ports or printer ports, whereas Terminal Server sessions might be using device redirection to point those device names to serial ports or printer ports on the Terminal Server client machine.

The solution to this problem was partitioning the view of the kernel object namespace provided to Win32 based on Terminal Server session id. This is done with the use of a set of symbolic links and object directories.

The basic idea is that session zero continues to use the \BaseNamedObjects object directory, as how things used to work on downlevel systems. In this object directory, there are a couple of new symbolic links:

  • \Local, which points to the session local namespace. For session zero, this symbolic link typically points to \BaseNamedObjects. For other sessions, it points to a “sessionized” namespace, such as \Sessions\<Terminal-Server-Session-ID>\BaseNamedObjects.
  • \Global, which always points to the session zero namespace (the “global” namespace). This always points to \BaseNamedObjects for all sessions.
  • \Session, which points to \Sessions\BNOLINKS. This latter symbolic link is not documented (except to say that it is “reserved for system use”), but its function is to allow one session (with the appropriate access granted to it) to create objects in an arbitrary session local namespace, by using a path in the form \Session\<Terminal-Server-Session-ID>\ObjectName. \Sessions\BNOLINKS is an object directory which contains a set of symbolic link objects, each named after a Terminal Server session ID. These links point to the appropriate “sessionized” BaseNamedObjects directory for each session (such as \BaseNamedObjects for session zero, \Sessions\1\BaseNamedObjects for session 1, and soforth).

For sessions other than session zero, a BasedNamedObjects directory named in the form of \Sessions\<Terminal-Server-Session-ID>\BaseNamedObjects is created. This is the session local namespace for that session, and it is what is linked to via the “\Local” symbolic link. Additionally, a corresponding symbolic link in \Sessions\BNOLINKS is created so that the (undocumented) “\Session” link works for the new session.

This scheme allows for maximum compatibility with pre-Terminal Server applications which are not aware of the “session isolation” concept, and need some help in order to have their named objects placed in a “sessionized” location where they will not conflict with other user sessions. A means for programs that truly need globally-accessible object names is also provided (the magical \Global prefix symbolic link), which is typically used by services and user-level UI applications that need to communicate with their privileged service counterpart.

In addition to the session isolation of kernel object names, “DOS device” names also became isolated based on Terminal Server session ID. The way this works differs between Windows 2000 and future OS versions, though; I’ll cover it in the next installment of this series. The basic idea for Windows 2000 is that each session got its own directory for DOS device names, but Windows XP and beyond go one step further to better accomodate the “runas” case.

2 Responses to “The kernel object namespace and Win32, part 2”

  1. […] As Ken discusses at length, objects created by users are created, by default, in a session-local namespace. So, consider the NdisMRegisterDevice() documentation: SymbolicName Pointer to an NDIS_STRING type containing a Unicode string that is the Win32-visible name of the device being registered. Typically, the SymbolicName has the following format: \DosDevices\SymbolicName. […]